Braccio robotico Arduino: servo, calcolo della coppia e Bluetooth
Come costruire un braccio robotico Arduino: struttura in MDF o stampa 3D, coppia del MG996R, controllo con potenziometro e joystick, PCA9685 e Bluetooth.
Un braccio robotico Arduino è un robot da scrivania che, grazie alle articolazioni mosse da servomotori, può afferrare un oggetto, sollevarlo, ruotare e posarlo altrove. Con base, spalla, gomito, polso e pinza, ti insegna in un solo progetto progettazione meccanica, scelta dei motori, gestione dell'alimentazione e programmazione. E il bello è che puoi costruirlo a casa con un Arduino Uno, qualche servo e parti in MDF o stampate in 3D, facendo lavorare sulla tua scrivania una piccola copia di un robot industriale.
In questa guida vediamo dall'inizio alla fine i bracci robotici a 4 e 6 assi: il materiale della struttura, il calcolo della coppia per scegliere tra SG90, MG90S e MG996R, l'alimentazione esterna a 5 V, il controllo con potenziometri e joystick, la registrazione e riproduzione dei movimenti, il driver per servo a 16 canali PCA9685, il controllo Bluetooth dallo smartphone e le soluzioni ai due problemi più frequenti: tremolii e reset. Se non sai ancora come funziona un servo, parti da Cos'è un servomotore?.



Come funziona un braccio robotico e quanti assi servono?
Immagina un braccio robotico come un braccio umano. In ogni articolazione c'è un servomotore e Arduino dice a ogni servo "vai a questo angolo". Grazie al potenziometro interno, il servo sa dove si trova il suo albero e mantiene l'angolo anche sotto carico. Cambiando insieme gli angoli delle articolazioni porti la pinza nel punto che vuoi. Il numero di movimenti indipendenti che un braccio può compiere si chiama gradi di libertà (DOF), o più semplicemente assi.
| Articolazione | Movimento | Carico | Servo consigliato |
|---|---|---|---|
| Base (rotazione) | Ruota il braccio a destra e a sinistra | Non solleva nulla ma sostiene tutto il braccio | MG996R + cuscinetto |
| Spalla | Solleva il braccio in avanti e indietro | L'articolazione più sollecitata | MG996R o servo della classe 20 kg·cm |
| Gomito | Piega l'avambraccio | Medio-alto | MG996R |
| Polso (su e giù) | Regola l'angolo della pinza | Basso | MG90S |
| Rotazione del polso | Ruota la pinza sul proprio asse | Molto basso | MG90S o SG90 |
| Pinza (gripper) | Afferra e rilascia l'oggetto | Forza di serraggio | SG90 o MG90S |
La maggior parte dei kit di "braccio robotico a 6 assi" ha 6 servo; poiché la pinza non conta come asse, tecnicamente si tratta di un braccio a 5 gradi di libertà più una pinza. Per il tuo primo braccio, un progetto a 4 assi (base, spalla, gomito, pinza) è il punto di partenza migliore: bastano 4 servo, 4 potenziometri e un Arduino Uno, il cablaggio resta semplice e i problemi di coppia sono rari. Le articolazioni del polso servono per tenere la pinza orizzontale o afferrare oggetti da angolazioni diverse; quando passi a 5–6 servo, il driver PCA9685 diventa quasi indispensabile.
Lista dei materiali
| Componente | Braccio a 4 assi | Braccio a 6 servo | Nota |
|---|---|---|---|
| Scheda di controllo | Arduino Uno o Nano | Arduino Uno, Nano o ESP32 | Gli ingressi extra A6 e A7 del Nano permettono più potenziometri |
| Servomotori | 4 × SG90 o MG90S | 3 × MG996R + 3 × MG90S | Verifica la scelta con il calcolo della coppia qui sotto |
| Driver per servo | Non serve | Modulo PCA9685 a 16 canali | Solo 2 fili di segnale in I2C |
| Alimentatore | 5 V 3 A | 5–6 V, almeno 5 A | I servo non si alimentano mai da Arduino |
| Condensatore | 470–1000 µF, 16 V | 1000–2200 µF, 16 V | Sulla linea di alimentazione dei servo, rispettando la polarità |
| Comandi | 4 potenziometri da 10 kΩ | 2 moduli joystick o un HC-05 | Puoi anche usarli insieme |
| Pulsanti | 2 (registra, riproduci) | Bastano i pulsanti dei joystick | Con INPUT_PULLUP niente resistenze |
| Meccanica | Parti in MDF da 3 mm o stampate in 3D | MDF da 4 mm, stampa 3D o staffe in alluminio | Cuscinetto 608, viti M3 e dadi autobloccanti |
Struttura meccanica: MDF o stampa 3D?
| Materiale | Pregi | Difetti | Ideale per |
|---|---|---|---|
| MDF da 3–4 mm (taglio laser) | Economico, leggero, facile da avvitare e incollare | Teme l'umidità, i fori delle viti si allargano col tempo | Primi bracci stile MeArm, progetti scolastici |
| Acrilico da 3 mm | Molto bello, non teme l'umidità | Fragile; può incrinarsi stringendo le viti | Progetti da esposizione |
| Stampa 3D (PLA / PETG) | Parti complesse, sedi dei servo su misura | Stampa lunga; il PLA si deforma col calore e sotto carico costante | Progetti personali; PETG per le parti portanti |
| Kit di staffe in alluminio | Molto rigido, parti pronte per il MG996R | Pesante e costoso, carica di più la spalla | Bracci a 6 servo per oggetti più pesanti |
| Cartone, bastoncini da gelato | Quasi gratis, prototipo rapido | Poco robusto, le articolazioni prendono gioco | Provare le misure, primi tentativi con i bambini |
- Tieni il braccio corto e leggero: Il carico sulla spalla cresce in proporzione diretta alla distanza. Un braccio da 24 cm invece di 30 cm riduce la coppia della spalla di circa un quinto.
- Metti i servo pesanti vicino alla base: Spostare il servo del gomito all'altezza della spalla e azionare il gomito con un'asta di spinta (parallelogramma) è un trucco furbo usato da bracci come il MeArm; la spalla non deve più sollevare quel servo.
- Usa un cuscinetto nella base: Non caricare tutto il peso del braccio sull'albero del servo della base. Un cuscinetto 608 (8 mm interno, 22 mm esterno, 7 mm di spessore; il classico da skateboard) o un cuscinetto per piatto girevole regge il carico e il servo si limita a ruotare.
- Sostieni le articolazioni da entrambi i lati: Mentre il servo tiene l'articolazione dal lato della squadretta, aggiungi un perno sul lato opposto con una vite M3 e un dado autobloccante. Così l'albero del servo non subisce flessione e gli ingranaggi durano molto di più.
- Usa squadrette metalliche: Monta su ogni MG996R una squadretta tonda metallica a 25 denti (25T) e fissala all'albero con la vite centrale. Le squadrette di plastica slittano e si spanano sulle articolazioni molto caricate.
- Aggiungi gomma alle dita della pinza: Una sottile striscia di gomma sulle punte permette di tenere gli oggetti senza farli scivolare e con meno forza di serraggio.
Scegliere i servo: SG90, MG90S o MG996R?
| Modello | Coppia | Velocità (per 60°) | Peso | Ingranaggi | Corrente di stallo | Ruolo nel braccio |
|---|---|---|---|---|---|---|
| SG90 | 1,8 kg·cm (4,8 V) | 0,10 s (4,8 V) | 9 g | Plastica | Circa 0,6–0,75 A | Pinza, polso leggero, piccolo braccio a 4 assi |
| MG90S | 1,8 kg·cm (4,8 V), 2,2 kg·cm (6 V) | 0,10 s (4,8 V) | 13,4 g | Metallo | Circa 0,7–1 A | Polso, rotazione del polso, pinza |
| MG996R | 9,4 kg·cm (4,8 V), 11 kg·cm (6 V) | 0,17 s (4,8 V) | 55 g | Metallo | 2,5 A (6 V) | Base, spalla, gomito |
| DS3218 | 19 kg·cm (5 V), 21,5 kg·cm (6,8 V) | 0,16 s (5 V) | 60 g | Metallo | Circa 2–3 A | Spalla di bracci lunghi o pesanti |
La coppia indicata in tabella è la coppia di stallo (stall torque): la forza massima che il servo fornisce prima che il suo albero si fermi, non un valore di lavoro continuo. Più un servo si avvicina a quel limite, più la sua corrente sale verso quella di stallo, si scalda e comincia a tremare. La regola pratica è che la coppia richiesta da un'articolazione non superi la metà della coppia di stallo del servo. Conta anche la tensione: il MG996R dà 9,4 kg·cm a 4,8 V e 11 kg·cm a 6 V, quindi lo stesso servo diventa circa il 17% più forte solo grazie alla tensione. Per questo con i bracci a MG996R conviene alimentare a 6 V, ma per SG90 e MG90S 6 V è il limite massimo. Per collegamenti e limiti del MG996R leggi anche la guida servomotore MG996R.

Calcolo della coppia: il servo della spalla regge questo braccio?
La coppia che un servo deve vincere è la somma della massa di ogni parte moltiplicata per la sua distanza orizzontale dall'asse dell'articolazione: Coppia (kg·cm) = Σ massa (kg) × distanza (cm). Il caso peggiore è con il braccio completamente disteso in orizzontale, perché tutte le distanze sono massime; con il braccio verticale il braccio di leva scende quasi a zero. Per passare ai newton metro moltiplica per 0,098 (1 kg·cm ≈ 0,098 N·m). Come esempio calcoliamo il carico sulla spalla di un braccio da scrivania con 12 cm dalla spalla al gomito, 12 cm dal gomito al polso, 6 cm dal polso alla punta della pinza e un MG996R nel gomito, con la pinza che tiene un oggetto da 50 g:
| Parte | Massa | Distanza dall'asse della spalla | Coppia |
|---|---|---|---|
| Parti del braccio superiore (MDF e viti) | 40 g | 6 cm (baricentro) | 0,04 × 6 = 0,24 kg·cm |
| Servo del gomito (MG996R) | 55 g | 12 cm | 0,055 × 12 = 0,66 kg·cm |
| Parti dell'avambraccio | 30 g | 18 cm | 0,03 × 18 = 0,54 kg·cm |
| Servo del polso + pinza (MG90S, SG90 e parti) | 50 g | 25 cm | 0,05 × 25 = 1,25 kg·cm |
| Oggetto afferrato | 50 g | 30 cm | 0,05 × 30 = 1,50 kg·cm |
| Totale | 225 g | — | 4,19 kg·cm (≈ 0,41 N·m) |
Da fermo, questo braccio richiede 4,19 kg·cm alla spalla. Per coprire il carico extra di accelerazioni e frenate e tenere il servo lontano dallo stallo, moltiplica per 2: 8,4 kg·cm. Quindi la spalla ha bisogno almeno di un MG996R (9,4 kg·cm a 4,8 V, 11 kg·cm a 6 V); gli 1,8–2,2 kg·cm di un SG90 o MG90S non smuoverebbero nemmeno questo braccio. Rifacendo il calcolo per il gomito, avambraccio (0,03 × 6), polso con pinza (0,05 × 13) e oggetto (0,05 × 18) danno 1,73 kg·cm, cioè 3,5 kg·cm con il margine di sicurezza: anche il gomito vuole un MG996R. Sul polso restano solo pinza e oggetto, il carico è di circa 0,4 kg·cm e un MG90S basta e avanza. Lo stesso calcolo ti dice anche qual è l'oggetto più pesante che il braccio può portare: aumenta la massa, ricalcola il totale e resta sotto la metà della coppia del servo.
Alimentazione: perché i servo non si alimentano da Arduino?
La maggior parte dei problemi di un braccio robotico nasce dall'alimentazione. Un MG996R assorbe 0,5–0,9 A in movimento e fino a 2,5 A in stallo; persino un piccolo SG90 può superare 0,6 A quando si blocca. Con Arduino Uno alimentato via USB, la corrente totale disponibile sul pin 5V è di circa 500 mA, il limite dell'USB, e una parte la consuma la scheda stessa. Quando tre servo grandi partono insieme, la tensione crolla, il microcontrollore si resetta e il braccio scatta nella posizione iniziale. La soluzione è alimentare i servo con una sorgente separata da 5–6 V e collegare insieme tutte le masse (GND); Arduino può continuare a essere alimentato via USB o dal suo alimentatore. Per le opzioni di alimentazione consulta la guida alimentazione di Arduino, e per stimare quanto dura un braccio a batteria usa il calcolatore di durata della batteria.
| Tipo di braccio | Corrente stimata | Alimentazione consigliata |
|---|---|---|
| Braccio piccolo con 4 × SG90 o MG90S | 0,5–1 A in movimento, picchi di 2–3 A | Alimentatore 5 V 3 A o modulo LM2596 (max 3 A, circa 2 A senza dissipatore) |
| Braccio a 6 servo: 3 × MG996R + 3 × MG90S | 2–3 A in movimento, 8–10 A se vanno tutti in stallo | Alimentatore switching 5–6 V da almeno 5 A (10 A per stare tranquillo) |
| Braccio portatile | Dipende dal braccio | LiPo 2S (7,4 V) + modulo step-down (UBEC) da 5 A o più regolato a 6 V |
| Sorgenti da evitare | — | Batteria da 9 V (non regge la corrente), il pin 5V di Arduino, 4 pile AA alcaline su un braccio con MG996R |
Collegamenti del braccio a 4 assi
La tabella qui sotto riporta il cablaggio del braccio a 4 assi con potenziometri per Arduino Uno e Raspberry Pi Pico; gli sketch di questa guida usano questi pin. Su Uno la libreria Servo può pilotare un servo da qualsiasi pin digitale, ma poiché usa il Timer1, analogWrite smette di funzionare sui pin 9 e 10 finché ci sono servo collegati. Puoi vedere la piedinatura della tua scheda nello strumento Pinout.
| Collegamento | Arduino Uno | Raspberry Pi Pico |
|---|---|---|
| Segnale servo della base (filo arancione) | D3 | GP10 |
| Segnale servo della spalla | D5 | GP11 |
| Segnale servo del gomito | D6 | GP12 |
| Segnale servo della pinza | D9 | GP13 |
| Cursore potenziometri 1–3 (base, spalla, gomito) | A0, A1, A2 | GP26, GP27, GP28 |
| Cursore potenziometro 4 (pinza) | A3 | Nessuno; la pinza usa il pulsante su GP14 |
| Piedini esterni dei potenziometri | 5V e GND | 3V3 e GND |
| Pulsanti registra e riproduci (altro lato a GND) | D7 e D8 | — |
| Filo rosso del servo (+) | Positivo esterno 5–6 V | Positivo esterno 5–6 V |
| Filo marrone del servo (−) | Negativo dell'alimentatore esterno + GND di Arduino | Negativo dell'alimentatore esterno + GND del Pico |

Calibra prima del montaggio: centra i servo
- Prima di montare le squadrette carica il codice qui sotto; tutti e quattro i servo vanno uno dopo l'altro a 90 gradi e restano lì.
- Tieni il braccio in una posa neutra (per esempio braccio superiore verticale, avambraccio orizzontale e pinza semiaperta), monta ogni squadretta sul dente più vicino a quella posa e fissala con la vite centrale.
- Nel codice imposta CENTER_ONLY a false, scegli un'articolazione con TEST e gira lentamente il potenziometro su A0.
- Osserva l'angolo nel Monitor seriale e annota l'angolo minimo e massimo che l'articolazione raggiunge senza urtare nulla né tirare i cavi.
- Fissa l'angolo chiuso della pinza nel punto in cui le dita si toccano appena; un servo che continua a voler stringere resta in stallo e si scalda.
- Scrivi i valori trovati negli array MIN_A e MAX_A degli sketch successivi.
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}C'è un dettaglio piccolo ma importante in questo codice: poiché servo.write(90) viene chiamato prima di attach(), il servo riceve l'angolo voluto già dal primo impulso. Se inverti l'ordine, la libreria invia prima il suo impulso predefinito di 1500 µs (circa 90°); se il tuo angolo iniziale non è 90, all'accensione il braccio scatta prima al centro e poi verso l'obiettivo. Avviare i servo uno alla volta a 300 ms di distanza distribuisce anche il picco di corrente all'accensione.
Controllare il braccio robotico con i potenziometri
Il metodo di controllo più intuitivo è un potenziometro per articolazione: l'articolazione segue l'angolo dell'albero del potenziometro, quindi fai un controllo di posizione. Se monti i potenziometri in un piccolo modellino del braccio (in cartone o stampato in 3D, con le stesse proporzioni), il braccio grande copia uno a uno i movimenti che fai con la mano. Le letture analogiche però oscillano per natura di qualche unità, e quell'oscillazione si trasforma in tremolio del servo; il codice prevede due contromisure.
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}L'array smooth è un semplice filtro passa-basso: a ogni ciclo si aggiunge solo il 20% della nuova lettura, così i salti si ammorbidiscono e il braccio risponde comunque in fretta. Con 0,1 al posto di 0,2 il movimento diventa più morbido ma più lento a reagire. La seconda contromisura è una banda morta: finché il nuovo angolo non differisce di almeno 2 gradi dall'ultimo scritto, al servo non arriva nulla e il tremolio a braccio fermo sparisce. Poiché map() converte l'escursione del potenziometro direttamente nei limiti sicuri di ogni articolazione, l'articolazione non arriva al finecorsa meccanico nemmeno con il potenziometro girato fino in fondo.
Registrare e riprodurre i movimenti
Quello che rende davvero robot un braccio è che ripeta da solo un movimento che gli hai mostrato. Il metodo è semplice: porti il braccio in una posa con i potenziometri e premi il pulsante di registrazione, e Arduino memorizza gli angoli delle quattro articolazioni. Dopo qualche posa premi riproduci e il braccio le ripete in ordine, ammorbidendo i passaggi tra l'una e l'altra. Le pose vengono scritte nella EEPROM da 1024 byte di Arduino Uno, quindi non si cancellano spegnendo la scheda; ogni posa occupa 4 byte, perciò una registrazione di 100 pose usa solo 401 byte.
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}| Azione | Cosa fai | Cosa fa il braccio |
|---|---|---|
| Salvare una posa | Pressione breve del pulsante di registrazione (D7) | Il LED lampeggia una volta, la posa viene scritta nella EEPROM |
| Cancellare le registrazioni | Tieni premuto il pulsante di registrazione per 2 secondi | Il LED lampeggia cinque volte, il contatore dei passi si azzera |
| Riprodurre | Premi e rilascia il pulsante di riproduzione (D8) | Il LED si accende, le pose si ripetono in ordine con passaggi morbidi |
| Fermare la riproduzione | Tieni premuto il pulsante di riproduzione durante la riproduzione | Il braccio completa la posa in corso e si ferma |
| Tornare alla modalità normale | Non fare nulla a fine riproduzione | Il braccio torna lentamente dove indicano i potenziometri, il LED si spegne |
La funzione moveTo() è il cuore dello sketch: trova l'articolazione con il percorso più lungo, divide il movimento in altrettanti passi e a ogni passo fa avanzare tutte le articolazioni in proporzione. Così arrivano tutte a destinazione nello stesso momento e il braccio si muove in modo fluido, non come un robot che muove un'articolazione alla volta. 12 ms per grado significano che un movimento di 90 gradi dura circa 1,1 secondi. Puoi abbassare il valore per una riproduzione più veloce, ma anche a vuoto un MG996R ruota di 60 gradi in 0,17 secondi, cioè circa 3 ms per grado; sotto questo valore i servo non riescono a seguire i comandi e il movimento diventa a scatti.
Driver per servo PCA9685: 6 servo e un segnale senza tremolii
Quando passi a 5–6 servo o aggiungi moduli come il Bluetooth, un modulo PCA9685 ti semplifica parecchio la vita. Questa scheda è un generatore PWM a 16 canali con risoluzione di 12 bit; comunica con Arduino su soli due fili tramite I2C e genera gli impulsi dei servo con il proprio clock, indipendentemente dal processore. L'indirizzo predefinito è 0x40; cambiando l'indirizzo con i ponticelli a saldare A0–A5 puoi collegare in catena fino a 62 schede, cioè 992 servo. A 50 Hz il periodo di 20 ms è diviso in 4096 passi, quindi un passo vale circa 4,9 µs; l'intervallo 544–2400 µs copre circa 380 passi, il che dà una risoluzione di circa mezzo grado.
| Pin del PCA9685 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| GND | GND | GND | GND |
| VCC (solo alimentazione del chip) | 5V | 3V3 | 3V3 |
| SDA | A4 | GPIO 21 | GP4 |
| SCL | A5 | GPIO 22 | GP5 |
| Morsetto V+ (alimentazione servo) | 5–6 V esterni | 5–6 V esterni | 5–6 V esterni |
| OE | Lascialo scollegato | Lascialo scollegato | Lascialo scollegato |
| Connettori servo 0–5 | Base, spalla, gomito, polso, rotazione del polso, pinza | Stesso ordine | Stesso ordine |
Controllare il braccio robotico con i joystick
Un joystick funziona in modo diverso da un potenziometro: quando lo lasci torna al centro. Se leghi l'angolo direttamente alla posizione del joystick, l'articolazione scatta a 90 gradi appena lo rilasci. Il metodo giusto è il controllo di velocità: più spingi il joystick, più veloce ruota l'articolazione, e quando lo lasci resta dov'è. Nel codice qui sotto due joystick muovono quattro articolazioni (quello sinistro base e spalla, quello destro gomito e polso); il pulsante del joystick sinistro apre e chiude la pinza, quello del destro riporta il braccio nella posa iniziale. Collega le uscite VRx e VRy del joystick sinistro ad A0 e A1, VRy e VRx del destro ad A2 e A3 e i pin SW a D2 e D4; i joystick si possono alimentare dal pin 5V di Arduino. Per compilare il codice installa Adafruit PWM Servo Driver Library dal Gestore librerie e accetta la dipendenza 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 evita che piccoli scostamenti come 490–530, letti con il joystick al centro, facciano scivolare il braccio da solo. MAX_SPEED stabilisce la velocità, in gradi al secondo, con il joystick spinto a fondo; 90 gradi al secondo è un valore sicuro per iniziare. Se un'articolazione va al contrario rispetto al joystick, non invertire i fili: imposta a -1 il valore corrispondente nell'array DIR. Il codice tiene per ogni articolazione un obiettivo (target) e una posizione reale (current); poiché la posizione reale raggiunge l'obiettivo con un limite di velocità, il braccio torna in modo fluido, senza scatti, anche quando premi il pulsante della posa iniziale. La rotazione del polso resta fissa a 90 gradi in questo sketch; puoi comandarla con il comando R della sezione Bluetooth. I dettagli di questa temporizzazione non bloccante sono spiegati in millis() invece di delay().
Controllo Bluetooth dallo smartphone (HC-05)
Il modulo HC-05 crea un collegamento seriale senza fili tra lo smartphone e Arduino. Il suo pin TXD va al D10 di Arduino, mentre il pin RXD si collega a D11 tramite un partitore di tensione: D11 → 1 kΩ → RXD → 2 kΩ → GND. Il partitore abbassa il segnale a 5 V di Arduino ai circa 3,3 V che si aspetta l'HC-05. La velocità dati predefinita è 9600 baud e il PIN di associazione di solito è 1234. Lo smartphone invia semplici comandi di testo: una lettera sceglie l'articolazione, il numero che segue indica l'angolo e un a capo o un punto e virgola chiude il comando.

| Comando | Significato | Esempio |
|---|---|---|
| B + angolo | Base | B90 |
| S + angolo | Spalla | S120 |
| E + angolo | Gomito | E45 |
| W + angolo | Polso (su e giù) | W100 |
| R + angolo | Rotazione del polso | R0 |
| G + angolo | Pinza | G110 (chiudi), G40 (apri) |
| H | Torna alla posa iniziale | H |
| K / P / X / C | Salva posa / riproduci in loop / ferma / cancella le pose | 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}In questo sketch i servo sono collegati al PCA9685 e non direttamente ad Arduino, ed è una scelta voluta. SoftwareSerial disattiva gli interrupt per circa 1 ms mentre riceve ogni byte; se i servo fossero pilotati dai pin di Arduino con la libreria Servo, in quel momento i loro impulsi si allungherebbero e il braccio avrebbe uno scatto a ogni comando. Poiché il PCA9685 genera da solo gli impulsi, il segnale resta stabile per quanto intenso sia il traffico Bluetooth. Ora anche registrazione e riproduzione si fanno dallo smartphone: porti il braccio in una posa con i cursori e invii K; dopo qualche posa, con P il braccio le ripete in loop e con X si ferma. In questa versione le pose restano nella RAM e si perdono quando spegni la scheda; se vuoi conservarle, aggiungi il metodo EEPROM dello sketch precedente.
Braccio robotico wireless con ESP32
Poiché l'ESP32 ha il Bluetooth classico integrato, l'HC-05 non serve: con la libreria BluetoothSerial la scheda compare sullo smartphone come "BlueGrays-RobotKol" e capisce gli stessi comandi. Collega il PCA9685 a GPIO 21 (SDA) e GPIO 22 (SCL) e alimenta VCC dal 3V3; i segnali dei servo escono così a 3,3 V, che la stragrande maggioranza dei servo legge senza problemi. BluetoothSerial funziona solo sull'ESP32 classico (ESP32-WROOM-32, DevKit); ESP32-S2, S3 e C3 non supportano il Bluetooth classico.
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}Braccio robotico con Raspberry Pi Pico (MicroPython)
Per pilotare servo con il Raspberry Pi Pico non serve alcuna libreria aggiuntiva: imposti il PWM a 50 Hz e indichi la larghezza dell'impulso in nanosecondi con duty_ns(). Con 16 canali PWM il Pico può pilotare 6 servo direttamente; le coppie di pin che condividono lo stesso slice hanno la stessa frequenza, ma dato che tutti i servo usano 50 Hz non è un problema. Il limite è sul lato analogico: il Pico ha solo tre pin ADC utilizzabili (GP26, GP27, GP28). Per questo nel codice qui sotto tre articolazioni sono comandate dai potenziometri e la pinza si apre e si chiude con un pulsante su GP14. Visto che il Pico lavora a 3,3 V, collega i potenziometri a 3V3; i servo restano alimentati da una sorgente esterna a 5 V.
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 loopUn passo avanti: la cinematica inversa
Finora abbiamo dato l'angolo di ogni articolazione uno per uno; si chiama cinematica diretta. La cinematica inversa fa il contrario: indichi il punto (x, y) che vuoi far raggiungere alla pinza e il codice calcola gli angoli necessari. Per un braccio a due segmenti con lunghezza spalla–gomito L1 e gomito–polso L2 si calcola prima D = (x² + y² − L1² − L2²) / (2·L1·L2). L'angolo del gomito è θ2 = acos(D) e quello della spalla θ1 = atan2(y, x) + atan2(L2·sin θ2, L1 + L2·cos θ2) (soluzione con gomito in alto). Per esempio, con L1 = L2 = 12 cm e un punto 15 cm davanti e 5 cm sopra la spalla si ottiene D ≈ −0,13, θ2 ≈ 97,6° e θ1 ≈ 67,2°: il braccio superiore punta 67 gradi sopra l'orizzontale e l'avambraccio si piega di 97,6 gradi verso il basso rispetto a esso. Se il valore assoluto di D supera 1, il punto è fuori dalla portata del braccio. L'angolo della base si calcola a parte, dalla posizione dell'obiettivo vista dall'alto. Quando converti i risultati in angoli dei servo, considera il verso di montaggio e il punto centrale di ciascun servo.
Tremolii e reset: errori comuni e soluzioni
| Sintomo | Causa probabile | Soluzione |
|---|---|---|
| I servo tremano e ronzano a braccio fermo | Rumore nelle letture dei potenziometri o alimentazione debole | Aggiungi un filtro di livellamento e una banda morta di 2°, usa un alimentatore esterno e un condensatore da 1000 µF |
| Arduino si resetta quando il braccio si muove, l'HC-05 perde la connessione | La corrente di spunto dei servo fa crollare la tensione | Alimenta i servo con una sorgente separata da 5–6 V, unisci le masse, avvia i servo uno alla volta |
| I servo hanno uno scatto a ogni comando Bluetooth | Gli interrupt di SoftwareSerial disturbano gli impulsi della libreria Servo | Sposta i servo su un PCA9685 o usa il Bluetooth integrato dell'ESP32 |
| All'accensione il braccio scatta bruscamente | I servo non ricordano l'ultima posizione e al primo comando vanno a piena velocità | Riporta il braccio nella posa iniziale prima di spegnere, chiama write() prima di attach() |
| La spalla non solleva il braccio o si abbassa lentamente | Coppia insufficiente | Fai il calcolo della coppia; usa un MG996R, un braccio più corto, un contrappeso o una molla |
| Un'articolazione si blocca a fine corsa e si scalda | Il servo spinge contro un finecorsa meccanico | Inserisci nel codice i limiti MIN_A e MAX_A trovati in calibrazione |
| Il servo della pinza si scalda mentre tiene un oggetto | La pinza continua a voler chiudere e il servo resta in stallo | Imposta l'angolo chiuso nel punto in cui tocca appena l'oggetto e aggiungi gomma alle dita |
| Il PCA9685 è collegato ma nessun servo si muove | Nessuna tensione sul morsetto V+ o massa non comune | Porta 5–6 V su V+ e controlla l'indirizzo I2C (0x40) |
| Un'articolazione slitta sotto carico | La squadretta di plastica si è spanata o manca la vite centrale | Usa una squadretta metallica e fissala all'albero con la vite centrale |
Idee di progetto con il braccio robotico
- Braccio che smista i colori: Leggi il colore di alcuni cubetti con un sensore di colore TCS3200 e fai posare al braccio ogni colore nella sua scatola.
- Controllo con i gesti: Con un MPU6050 su un guanto, il braccio robotico si inclina come il tuo polso.
- Telecomando wireless: Collega due joystick a un secondo Arduino e invia i comandi con un nRF24L01; ottieni un telecomando che non ha bisogno dello smartphone.
- Controllo dal browser: Crea dei cursori su una pagina web con un ESP32 e comanda il braccio da qualsiasi dispositivo della stessa rete Wi-Fi; un WebSocket su ESP32 riduce al minimo la latenza.
- Prelievo dal nastro: Costruisci un piccolo nastro trasportatore con un motore passo-passo; quando un TCRT5000 vede un oggetto, il braccio lo preleva dal nastro.
- Gara e progetto scolastico: Un braccio che registra e riproduce i movimenti è un'ottima scelta tra le idee per progetti da concorso, perché mostra insieme meccanica, elettronica e software.
Un braccio robotico Arduino ti insegna nello stesso momento progettazione meccanica, calcolo della coppia, gestione dell'alimentazione e programmazione di movimenti fluidi, e cresce con ogni ora che gli dedichi. Inizia con un braccio a 4 servo comandato da potenziometri, aggiungi registrazione e riproduzione, poi passa a 6 servo con PCA9685 e Bluetooth. Nell'app BlueGrays trovi progetti come il controllo dei servo con potenziometro e joystick, il controllo Bluetooth dallo smartphone e una coreografia con 32 servo, completi di schemi elettrici e codice passo passo, così puoi provare prima ogni articolazione del tuo braccio da sola.
Domande frequenti
Quale servo usare per un braccio robotico Arduino?
Per le articolazioni che reggono il carico, come base, spalla e gomito, il MG996R con ingranaggi metallici e 9–11 kg·cm di coppia è un'ottima scelta. Per le articolazioni leggere, come polso e pinza, bastano un MG90S o un SG90. I piccoli bracci fatti solo con SG90 funzionano se restano corti e leggeri, ma sollevano solo oggetti di qualche decina di grammi.
Che alimentatore serve per un braccio robotico?
Per un piccolo braccio con 4 servo SG90 o MG90S basta un alimentatore da 5 V 3 A. Per un braccio a 6 servo con 3 MG996R e 3 servo piccoli serve un alimentatore switching da 5–6 V e almeno 5 A, meglio 10 A per avere margine. Non dimenticare di collegare il negativo dell'alimentatore al GND di Arduino.
Quanti servo si possono collegare ad Arduino?
La libreria Servo gestisce fino a 12 servo su Arduino Uno e 48 sul Mega. Il vero limite però è la corrente: tutti i servo vanno alimentati da una sorgente esterna. Un modulo PCA9685 pilota 16 servo usando solo due pin I2C e si può collegare in catena fino a 62 moduli.
Perché i servo del mio braccio robotico tremano?
Le cause più comuni sono un'alimentazione insufficiente, la mancanza di una massa comune e il rumore nelle letture dei potenziometri. Usa un alimentatore esterno con un condensatore da 1000 µF sulla linea dei servo e applica nel codice un filtro di livellamento e una banda morta. Se usi SoftwareSerial insieme alla libreria Servo, spostare i servo su un PCA9685 elimina del tutto il tremolio.
Quanto peso può sollevare un braccio robotico con SG90?
La coppia di stallo del SG90 è di circa 1,8 kg·cm; per un uso sicuro considera la metà, cioè 0,9 kg·cm. Dato che il peso del braccio e dei servo consuma già parte di questo margine, in pratica un braccio con SG90 lungo circa 15 cm porta solo oggetti leggeri da 20–30 g, come un tappo di bottiglia o un piccolo cubetto di spugna.
Come si controlla un braccio robotico dallo smartphone?
Si collega ad Arduino un modulo Bluetooth HC-05 e lo smartphone invia comandi di testo come "S120" da un terminale seriale Bluetooth o da un'app di controllo con cursori. Con un ESP32 non serve un modulo aggiuntivo grazie al Bluetooth integrato. L'HC-05 non funziona con l'iPhone, quindi per l'iPhone serve un modulo BLE o l'ESP32 BLE.
Progetti da realizzare dopo questo articolo
Vedi tutti i progetti
Funzionamento del servomotore con potenziometro
Mentre giri la manopola del potenziometro, il braccio del servomotore ruota insieme a lei: un'estremità della manopola corrisponde a zero gradi, l'altra a mezzo giro. L'Arduino legge di continuo la po

Servocomando con joystick
Comanda due motori con un joystick, proprio come se girassi una telecamera di sicurezza. Spingendo la levetta a destra o a sinistra il servomotore in basso ruota piano, spingendola su o giù quello in

Utilizzo del servomotore
Il braccio di un piccolo servomotore ruota a turno in tre posizioni: tutto all'inizio, esattamente a metà e tutto alla fine, aspettando due secondi a ogni fermata. L'Arduino dice al motore a quale ang

Servomotore ESP32 (controllo tramite potenziometro)
In questo progetto controlliamo un servomotore SG90 tramite un potenziometro. Regoliamo l'angolo del servomotore mappando il valore analogico letto dal potenziometro su un intervallo compreso tra 0 e 180 gradi. La libreria ESP32Servo genera segnali per servomotori sui GPIO adatti dell'ESP32 che possono funzionare come uscite; in questo progetto si utilizza GPIO 18. Si tratta di un metodo di controllo fondamentale per bracci robotici, gimbal per telecamere e meccanismi di porte automatiche.

Controllare un LED dal telefono tramite Bluetooth
Una piccola prova per accendere e spegnere le luci della tua stanza dal telefono. Il modulo Bluetooth passa all'Arduino le lettere che invii dal telefono; una lettera accende il LED rosso, un'altra qu

Auto controllata via Bluetooth con L298N
Trasforma il telefono in un telecomando e guida la tua auto robot. L'Arduino riceve tramite un modulo Bluetooth i comandi di un'app di controllo remoto sul telefono e fa girare le ruote con un driver

Coreografia di servo in cerchio - Animazioni con 32 servomotori
Un progetto di animazione visiva che utilizza 32 servomotori disposti in cerchio su un Arduino Mega. I servo sono gestiti in un unico array e collegati ai pin 22-53 del Mega per visualizzare quattro diverse sequenze di movimento: una vibrazione caotica in cui tutti i servo si muovono ad angoli casuali, uno sweep sincrono in cui si muovono tutti allo stesso tempo, un'onda che ruota dolcemente intorno a un cerchio e infine un ago di bussola che oscilla a destra e a sinistra. L'effetto onda vortico
Altri articoli
App BlueGrays
Costruisci questo circuito passo passo sul telefono
Schema, codice ed elenco componenti in un’unica schermata. Oltre 200 progetti Arduino, ESP32 e Pico da realizzare.
Inquadra con il telefono
Punta la fotocamera sul codice: si apre lo store del tuo telefono.
oppure apri lo store

