Bras robotique Arduino : servos, couple, PCA9685 et Bluetooth
Fabriquer un bras robotique Arduino : structure en MDF ou imprimée en 3D, couple du MG996R, pilotage par potentiomètre et joystick, PCA9685 et Bluetooth.
Un bras robotique Arduino est un robot de bureau dont les articulations, animées par des servomoteurs, lui permettent de saisir un objet, de le soulever, de pivoter et de le déposer ailleurs. Avec sa base, son épaule, son coude, son poignet et sa pince, il t'apprend en un seul projet la conception mécanique, le choix des moteurs, la gestion de l'alimentation et la programmation. Mieux encore, tu peux le fabriquer chez toi avec un Arduino Uno, quelques servos et des pièces en MDF ou imprimées en 3D, et faire tourner sur ton bureau une petite copie d'un robot industriel.
Dans ce guide, on passe en revue les bras robotiques à 4 et 6 axes de bout en bout : le matériau de la structure, un calcul de couple pour choisir entre SG90, MG90S et MG996R, l'alimentation externe en 5 V, le pilotage par potentiomètres et joysticks, l'enregistrement et la relecture des mouvements, le driver de servos 16 canaux PCA9685, le contrôle Bluetooth depuis le téléphone et les solutions aux deux problèmes les plus fréquents : les tremblements et les resets. Si tu ne sais pas encore comment fonctionne un servo, commence par Qu'est-ce qu'un servomoteur ?.



Comment fonctionne un bras robotique et combien d'axes faut-il ?
Imagine un bras robotique comme un bras humain. Chaque articulation possède un servomoteur, et l'Arduino dit à chaque servo « va à cet angle ». Grâce au potentiomètre qu'il contient, le servo sait où se trouve son axe et maintient cet angle même sous charge. En changeant les angles des articulations ensemble, tu amènes la pince où tu veux. Le nombre de mouvements indépendants d'un bras s'appelle ses degrés de liberté (DOF), ou plus simplement ses axes.
| Articulation | Mouvement | Charge | Servo conseillé |
|---|---|---|---|
| Base (rotation) | Fait pivoter le bras à gauche et à droite | Ne soulève rien mais porte tout le bras | MG996R + roulement |
| Épaule | Lève le bras vers l'avant et l'arrière | L'articulation la plus sollicitée | MG996R ou servo de la classe 20 kg·cm |
| Coude | Plie l'avant-bras | Moyenne à forte | MG996R |
| Poignet (haut-bas) | Règle l'angle de la pince | Faible | MG90S |
| Rotation du poignet | Fait tourner la pince sur son axe | Très faible | MG90S ou SG90 |
| Pince (gripper) | Saisit et relâche l'objet | Force de serrage | SG90 ou MG90S |
La plupart des kits de « bras robotique 6 axes » comptent 6 servos ; comme la pince n'est pas un axe, il s'agit techniquement d'un bras à 5 degrés de liberté plus une pince. Pour ton premier bras, une conception à 4 axes (base, épaule, coude, pince) est le meilleur départ : 4 servos, 4 potentiomètres et un Arduino Uno suffisent, le câblage reste simple et les problèmes de couple sont rares. Les articulations du poignet servent à garder la pince horizontale ou à saisir des objets sous différents angles ; dès que tu passes à 5–6 servos, le driver PCA9685 devient presque indispensable.
Liste du matériel
| Pièce | Bras à 4 axes | Bras à 6 servos | Remarque |
|---|---|---|---|
| Carte de contrôle | Arduino Uno ou Nano | Arduino Uno, Nano ou ESP32 | Les entrées supplémentaires A6 et A7 du Nano permettent plus de potentiomètres |
| Servomoteurs | 4 × SG90 ou MG90S | 3 × MG996R + 3 × MG90S | Vérifie ton choix avec le calcul de couple ci-dessous |
| Driver de servos | Inutile | Module PCA9685 16 canaux | Seulement 2 fils de signal en I2C |
| Alimentation | Bloc 5 V 3 A | 5–6 V, au moins 5 A | Les servos ne sont jamais alimentés par l'Arduino |
| Condensateur | 470–1000 µF, 16 V | 1000–2200 µF, 16 V | Sur la ligne d'alimentation des servos, attention à la polarité |
| Commandes | 4 potentiomètres de 10 kΩ | 2 modules joystick ou un HC-05 | Tu peux aussi combiner les deux |
| Boutons | 2 (enregistrer, lire) | Les boutons des joysticks suffisent | Pas de résistance avec INPUT_PULLUP |
| Mécanique | Pièces en MDF 3 mm ou imprimées en 3D | MDF 4 mm, impression 3D ou équerres en aluminium | Roulement 608, vis M3 et écrous freins |
Structure mécanique : MDF ou impression 3D ?
| Matériau | Points forts | Points faibles | Pour qui ? |
|---|---|---|---|
| MDF 3–4 mm (découpe laser) | Bon marché, léger, facile à visser et à coller | Craint l'humidité, les trous de vis s'agrandissent avec le temps | Premiers bras façon MeArm, projets scolaires |
| Acrylique 3 mm | Très joli, insensible à l'humidité | Cassant ; peut se fissurer au serrage des vis | Projets d'exposition |
| Impression 3D (PLA / PETG) | Pièces complexes, logements de servo sur mesure | Impression longue ; le PLA se déforme à la chaleur et sous charge permanente | Tes propres conceptions ; PETG pour les pièces porteuses |
| Kit d'équerres en aluminium | Très rigide, pièces prêtes pour le MG996R | Lourd et cher, charge davantage l'épaule | Bras à 6 servos pour des objets plus lourds |
| Carton, bâtonnets de glace | Presque gratuit, prototype rapide | Peu solide, les articulations prennent du jeu | Tester les dimensions, premiers essais avec des enfants |
- Garde le bras court et léger : La charge sur l'épaule augmente proportionnellement à la distance. Un bras de 24 cm au lieu de 30 cm réduit le couple de l'épaule d'environ un cinquième.
- Place les servos lourds près de la base : Descendre le servo du coude au niveau de l'épaule et entraîner le coude par une biellette (parallélogramme) est une astuce utilisée par des bras comme le MeArm ; l'épaule n'a plus à soulever ce servo.
- Utilise un roulement dans la base : Ne fais pas porter tout le poids du bras à l'axe du servo de base. Un roulement 608 (8 mm intérieur, 22 mm extérieur, 7 mm d'épaisseur ; le roulement de skateboard) ou un roulement de plateau tournant encaisse la charge, le servo ne fait que tourner.
- Soutiens les articulations des deux côtés : Pendant que le servo tient l'articulation côté palonnier, ajoute un pivot du côté opposé avec une vis M3 et un écrou frein. L'axe du servo ne subit alors aucune flexion et les engrenages durent bien plus longtemps.
- Utilise des palonniers métalliques : Monte sur chaque MG996R un palonnier rond métallique à 25 dents (25T) et fixe-le sur l'axe avec la vis centrale. Les palonniers en plastique patinent et perdent leurs cannelures sur les articulations très chargées.
- Ajoute du caoutchouc aux doigts de la pince : Une fine bande de caoutchouc au bout des doigts permet de tenir les objets sans qu'ils glissent, avec moins de force de serrage.
Choisir ses servos : SG90, MG90S ou MG996R ?
| Modèle | Couple | Vitesse (pour 60°) | Poids | Pignons | Courant de blocage | Rôle dans le bras |
|---|---|---|---|---|---|---|
| SG90 | 1,8 kg·cm (4,8 V) | 0,10 s (4,8 V) | 9 g | Plastique | Environ 0,6–0,75 A | Pince, poignet léger, petit bras à 4 axes |
| MG90S | 1,8 kg·cm (4,8 V), 2,2 kg·cm (6 V) | 0,10 s (4,8 V) | 13,4 g | Métal | Environ 0,7–1 A | Poignet, rotation du poignet, pince |
| MG996R | 9,4 kg·cm (4,8 V), 11 kg·cm (6 V) | 0,17 s (4,8 V) | 55 g | Métal | 2,5 A (6 V) | Base, épaule, coude |
| DS3218 | 19 kg·cm (5 V), 21,5 kg·cm (6,8 V) | 0,16 s (5 V) | 60 g | Métal | Environ 2–3 A | Épaule des bras longs ou lourds |
Le couple indiqué dans le tableau est le couple de blocage (stall torque) : la force maximale que le servo fournit avant que son axe ne s'arrête, et non une valeur de fonctionnement continu. Plus un servo approche de cette limite, plus son courant monte vers le courant de blocage, il chauffe et se met à trembler. La règle pratique : le couple dont une articulation a besoin ne doit pas dépasser la moitié du couple de blocage du servo. La tension compte aussi : le MG996R donne 9,4 kg·cm sous 4,8 V et 11 kg·cm sous 6 V, le même servo gagne donc environ 17 % de force grâce à la seule tension. C'est pourquoi une alimentation en 6 V est judicieuse pour les bras à MG996R, mais 6 V est la limite haute pour les SG90 et MG90S. Pour le câblage et les limites du MG996R, consulte aussi le guide servomoteur MG996R.

Calcul du couple : le servo de l'épaule peut-il soulever ce bras ?
Le couple qu'un servo doit fournir est la somme des masses de chaque pièce multipliées par leur distance horizontale à l'axe de l'articulation : Couple (kg·cm) = Σ masse (kg) × distance (cm). Le pire cas, c'est le bras tendu à l'horizontale, car toutes les distances sont alors maximales ; bras vertical, ce bras de levier tombe presque à zéro. Pour convertir en newton-mètres, multiplie par 0,098 (1 kg·cm ≈ 0,098 N·m). Prenons l'exemple d'un bras de bureau avec 12 cm de l'épaule au coude, 12 cm du coude au poignet, 6 cm du poignet au bout de la pince et un MG996R au coude, la pince tenant un objet de 50 g :
| Pièce | Masse | Distance à l'axe de l'épaule | Couple |
|---|---|---|---|
| Pièces du bras (MDF et vis) | 40 g | 6 cm (centre de gravité) | 0,04 × 6 = 0,24 kg·cm |
| Servo du coude (MG996R) | 55 g | 12 cm | 0,055 × 12 = 0,66 kg·cm |
| Pièces de l'avant-bras | 30 g | 18 cm | 0,03 × 18 = 0,54 kg·cm |
| Servo du poignet + pince (MG90S, SG90 et pièces) | 50 g | 25 cm | 0,05 × 25 = 1,25 kg·cm |
| Objet tenu | 50 g | 30 cm | 0,05 × 30 = 1,50 kg·cm |
| Total | 225 g | — | 4,19 kg·cm (≈ 0,41 N·m) |
À l'arrêt, ce bras demande 4,19 kg·cm à l'épaule. Pour couvrir la charge supplémentaire lors des accélérations et freinages, et garder le servo loin du blocage, multiplie par 2 : 8,4 kg·cm. L'épaule a donc besoin d'au moins un MG996R (9,4 kg·cm sous 4,8 V, 11 kg·cm sous 6 V) ; les 1,8–2,2 kg·cm d'un SG90 ou d'un MG90S ne feraient même pas bouger ce bras. En refaisant le calcul pour le coude, l'avant-bras (0,03 × 6), le poignet avec la pince (0,05 × 13) et l'objet (0,05 × 18) totalisent 1,73 kg·cm, soit 3,5 kg·cm avec la marge de sécurité : le coude réclame lui aussi un MG996R. Au poignet, il ne reste que la pince et l'objet, la charge tourne autour de 0,4 kg·cm et un MG90S suffit largement. Le même calcul te donne aussi l'objet le plus lourd que le bras peut porter : augmente la masse, recalcule le total et reste sous la moitié du couple du servo.
Alimentation : pourquoi les servos ne sont pas alimentés par l'Arduino ?
La plupart des problèmes de bras robotique viennent de l'alimentation. Un MG996R consomme 0,5–0,9 A en mouvement et jusqu'à 2,5 A bloqué ; même un petit SG90 peut dépasser 0,6 A en blocage. Quand l'Arduino Uno est alimenté par USB, le courant total disponible sur sa broche 5V tourne autour de 500 mA, la limite de l'USB, et la carte en consomme déjà une partie. Quand trois gros servos démarrent en même temps, la tension s'effondre, le microcontrôleur redémarre et le bras saute à sa position de départ. La solution : alimenter les servos avec une source séparée de 5–6 V et relier toutes les masses (GND) entre elles ; l'Arduino peut rester alimenté par USB ou par son propre bloc secteur. Pour les options d'alimentation, consulte le guide alimentation de l'Arduino, et pour estimer l'autonomie d'un bras sur batterie, utilise le calculateur d'autonomie de batterie.
| Type de bras | Courant estimé | Alimentation conseillée |
|---|---|---|
| Petit bras à 4 × SG90 ou MG90S | 0,5–1 A en mouvement, pics de 2–3 A | Bloc 5 V 3 A ou module LM2596 (3 A max., environ 2 A sans dissipateur) |
| Bras à 6 servos : 3 × MG996R + 3 × MG90S | 2–3 A en mouvement, 8–10 A si tous bloquent | Alimentation à découpage 5–6 V d'au moins 5 A (10 A pour être tranquille) |
| Bras portable | Selon le bras | LiPo 2S (7,4 V) + module abaisseur (UBEC) de 5 A ou plus réglé sur 6 V |
| Sources à éviter | — | Pile 9 V (ne fournit pas le courant), la broche 5V de l'Arduino, 4 piles AA alcalines sur un bras à MG996R |
Câblage du bras à 4 axes
Le tableau ci-dessous donne le câblage du bras à 4 axes piloté par potentiomètres pour l'Arduino Uno et le Raspberry Pi Pico ; les programmes de ce guide utilisent ces broches. Sur l'Uno, la bibliothèque Servo peut piloter un servo depuis n'importe quelle broche numérique, mais comme elle utilise le Timer1, analogWrite ne fonctionne plus sur les broches 9 et 10 tant que des servos sont attachés. Tu peux voir le brochage de ta carte dans l'outil Pinout.
| Connexion | Arduino Uno | Raspberry Pi Pico |
|---|---|---|
| Signal servo de base (fil orange) | D3 | GP10 |
| Signal servo d'épaule | D5 | GP11 |
| Signal servo de coude | D6 | GP12 |
| Signal servo de pince | D9 | GP13 |
| Curseur des potentiomètres 1–3 (base, épaule, coude) | A0, A1, A2 | GP26, GP27, GP28 |
| Curseur du potentiomètre 4 (pince) | A3 | Aucun ; la pince passe par le bouton sur GP14 |
| Pattes extérieures des potentiomètres | 5V et GND | 3V3 et GND |
| Boutons enregistrer et lire (autre côté au GND) | D7 et D8 | — |
| Fil rouge du servo (+) | Plus externe 5–6 V | Plus externe 5–6 V |
| Fil marron du servo (−) | Moins de l'alimentation externe + GND de l'Arduino | Moins de l'alimentation externe + GND du Pico |

Calibrer avant l'assemblage : centrer les servos
- Avant de monter les palonniers, téléverse le code ci-dessous ; les quatre servos vont l'un après l'autre à 90 degrés et y restent.
- Tiens le bras dans une pose neutre (par exemple bras vertical, avant-bras horizontal, pince à moitié ouverte), place chaque palonnier sur la cannelure la plus proche de cette pose et fixe-le avec la vis centrale.
- Passe CENTER_ONLY à false dans le code, choisis une articulation avec TEST et tourne lentement le potentiomètre sur A0.
- Surveille l'angle dans le moniteur série et note l'angle minimal et maximal que l'articulation atteint sans rien heurter ni tirer sur les câbles.
- Fixe l'angle fermé de la pince au moment où les doigts se touchent tout juste ; un servo qui continue de vouloir serrer reste bloqué et chauffe.
- Reporte les valeurs trouvées dans les tableaux MIN_A et MAX_A des programmes suivants.
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}Il y a un détail petit mais important dans ce code : comme servo.write(90) est appelé avant attach(), le servo reçoit l'angle voulu dès la première impulsion. Si tu inverses l'ordre, la bibliothèque envoie d'abord son impulsion par défaut de 1500 µs (environ 90°) ; si ton angle de départ n'est pas 90, le bras saute d'abord au milieu puis vers la cible à la mise sous tension. Démarrer les servos un par un avec 300 ms d'écart répartit aussi le pic de courant au démarrage.
Piloter le bras robotique avec des potentiomètres
La méthode la plus intuitive consiste à utiliser un potentiomètre par articulation : l'articulation prend l'angle de l'axe du potentiomètre, c'est donc un contrôle en position. Si tu montes les potentiomètres dans une petite maquette du bras (en carton ou imprimée en 3D, aux mêmes proportions), le grand bras copie à l'identique les mouvements que tu fais à la main. Les lectures analogiques fluctuent cependant naturellement de quelques points, et ces fluctuations se traduisent par des tremblements du servo ; le code prévoit deux parades.
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}Le tableau smooth est un filtre passe-bas simple : à chaque tour, seuls 20 % de la nouvelle lecture sont ajoutés, ce qui lisse les à-coups tout en gardant un bras réactif. Avec 0,1 au lieu de 0,2, le mouvement devient plus doux mais plus lent à réagir. La seconde parade est une zone morte : tant que le nouvel angle ne diffère pas d'au moins 2 degrés du dernier angle écrit, rien n'est envoyé au servo, ce qui supprime les tremblements à l'arrêt. Comme map() convertit directement la plage du potentiomètre vers les limites sûres de chaque articulation, celle-ci n'atteint jamais sa butée mécanique, même potentiomètre tourné à fond.
Enregistrer et rejouer les mouvements
Ce qui fait vraiment d'un bras un robot, c'est qu'il répète tout seul un mouvement que tu lui as montré. La méthode est simple : tu amènes le bras dans une pose avec les potentiomètres et tu appuies sur le bouton d'enregistrement, l'Arduino mémorise alors les angles des quatre articulations. Après quelques poses, appuie sur lecture et le bras les rejoue dans l'ordre en adoucissant les transitions. Les poses sont écrites dans l'EEPROM de 1024 octets de l'Arduino Uno et survivent donc à une coupure de courant ; chaque pose occupe 4 octets, un enregistrement de 100 poses n'utilise que 401 octets.
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}| Action | Ce que tu fais | Ce que fait le bras |
|---|---|---|
| Enregistrer une pose | Appui court sur le bouton d'enregistrement (D7) | La LED clignote une fois, la pose est écrite dans l'EEPROM |
| Effacer les enregistrements | Maintiens le bouton d'enregistrement 2 secondes | La LED clignote cinq fois, le compteur de pas revient à zéro |
| Lire | Appuie puis relâche le bouton de lecture (D8) | La LED s'allume, les poses sont rejouées dans l'ordre avec des transitions douces |
| Arrêter la lecture | Maintiens le bouton de lecture pendant la lecture | Le bras termine la pose en cours et s'arrête |
| Retour au mode normal | Ne fais rien à la fin de la lecture | Le bras revient doucement à la position indiquée par les potentiomètres, la LED s'éteint |
La fonction moveTo() est le cœur du programme : elle cherche l'articulation qui a le plus long chemin à parcourir, découpe le mouvement en autant de pas et fait avancer toutes les articulations proportionnellement à chaque pas. Ainsi, toutes arrivent à destination en même temps et le bras se déplace avec fluidité, au lieu de bouger une articulation après l'autre. 12 ms par degré signifient qu'un mouvement de 90 degrés dure environ 1,1 seconde. Tu peux baisser cette valeur pour une lecture plus rapide, mais même à vide un MG996R tourne de 60 degrés en 0,17 seconde, soit environ 3 ms par degré ; en dessous, les servos ne suivent plus les commandes et le mouvement devient saccadé.
Driver de servos PCA9685 : 6 servos et un signal sans tremblement
Dès que tu passes à 5–6 servos ou que tu ajoutes des modules comme le Bluetooth, un module PCA9685 te simplifie beaucoup la vie. Cette carte est un générateur PWM 16 canaux d'une résolution de 12 bits ; elle dialogue avec l'Arduino par seulement deux fils en I2C et génère les impulsions des servos avec sa propre horloge, indépendamment du processeur. Son adresse par défaut est 0x40 ; en changeant l'adresse avec les ponts de soudure A0–A5, tu peux chaîner jusqu'à 62 cartes, soit 992 servos. À 50 Hz, la période de 20 ms est divisée en 4096 pas, un pas vaut donc environ 4,9 µs ; la plage 544–2400 µs couvre environ 380 pas, ce qui donne une résolution d'environ un demi-degré.
| Broche du PCA9685 | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| GND | GND | GND | GND |
| VCC (alimentation de la puce seulement) | 5V | 3V3 | 3V3 |
| SDA | A4 | GPIO 21 | GP4 |
| SCL | A5 | GPIO 22 | GP5 |
| Bornier V+ (alimentation des servos) | 5–6 V externe | 5–6 V externe | 5–6 V externe |
| OE | Laisser libre | Laisser libre | Laisser libre |
| Connecteurs de servo 0–5 | Base, épaule, coude, poignet, rotation du poignet, pince | Même ordre | Même ordre |
Piloter le bras robotique avec des joysticks
Un joystick ne fonctionne pas comme un potentiomètre : relâché, il revient au centre. Si tu lies l'angle directement à la position du joystick, l'articulation saute à 90 degrés dès que tu le lâches. La bonne méthode est le contrôle en vitesse : plus tu pousses le joystick, plus l'articulation tourne vite, et quand tu le relâches, elle reste où elle est. Dans le code ci-dessous, deux joysticks pilotent quatre articulations (joystick gauche pour la base et l'épaule, joystick droit pour le coude et le poignet) ; le bouton du joystick gauche ouvre et ferme la pince, celui de droite ramène le bras en position de départ. Branche les sorties VRx et VRy du joystick gauche sur A0 et A1, VRy et VRx du joystick droit sur A2 et A3, et les broches SW sur D2 et D4 ; les joysticks peuvent être alimentés par la broche 5V de l'Arduino. Pour compiler le code, installe Adafruit PWM Servo Driver Library depuis le gestionnaire de bibliothèques et accepte la dépendance 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 empêche les petits écarts, comme 490–530, lus au centre de faire dériver le bras tout seul. MAX_SPEED fixe la vitesse, en degrés par seconde, joystick poussé à fond ; 90 degrés par seconde est une valeur sûre pour commencer. Si une articulation va dans le sens inverse du joystick, ne touche pas aux fils : passe à -1 la valeur correspondante du tableau DIR. Le code garde pour chaque articulation une cible (target) et une position réelle (current) ; comme la position réelle rejoint la cible avec une vitesse limitée, le bras revient en douceur, sans à-coup, même quand tu appuies sur le bouton de position de départ. La rotation du poignet reste fixée à 90 degrés dans ce programme ; tu peux la piloter avec la commande R de la partie Bluetooth. Les détails de cette temporisation non bloquante sont expliqués dans millis() ou delay().
Contrôle Bluetooth depuis le téléphone (HC-05)
Le module HC-05 crée une liaison série sans fil entre ton téléphone et l'Arduino. Sa broche TXD va sur la D10 de l'Arduino, et sa broche RXD se branche sur la D11 via un pont diviseur de tension : D11 → 1 kΩ → RXD → 2 kΩ → GND. Le pont abaisse le signal 5 V de l'Arduino aux 3,3 V environ qu'attend le HC-05. Le débit par défaut est de 9600 bauds et le code d'appairage est généralement 1234. Le téléphone envoie de simples commandes texte : une lettre choisit l'articulation, le nombre qui suit donne l'angle, et un retour à la ligne ou un point-virgule termine la commande.

| Commande | Signification | Exemple |
|---|---|---|
| B + angle | Base | B90 |
| S + angle | Épaule | S120 |
| E + angle | Coude | E45 |
| W + angle | Poignet (haut-bas) | W100 |
| R + angle | Rotation du poignet | R0 |
| G + angle | Pince | G110 (fermer), G40 (ouvrir) |
| H | Retour à la position de départ | H |
| K / P / X / C | Enregistrer la pose / lire en boucle / arrêter / effacer les poses | 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}Dans ce programme, les servos sont reliés au PCA9685 et non directement à l'Arduino, et c'est voulu. SoftwareSerial coupe les interruptions pendant environ 1 ms à la réception de chaque octet ; si les servos étaient pilotés depuis les broches de l'Arduino avec la bibliothèque Servo, leurs impulsions s'allongeraient pendant ce temps et le bras tressauterait à chaque commande. Comme le PCA9685 génère lui-même les impulsions, le signal reste stable quel que soit le trafic Bluetooth. L'enregistrement et la lecture se font désormais aussi depuis le téléphone : amène le bras dans une pose avec les curseurs et envoie K ; après quelques poses, P fait rejouer le bras en boucle et X l'arrête. Dans cette version, les poses sont gardées en RAM et disparaissent à l'extinction ; si tu veux les conserver, ajoute la méthode EEPROM du programme précédent.
Bras robotique sans fil avec un ESP32
Comme l'ESP32 intègre le Bluetooth classique, plus besoin de HC-05 : avec la bibliothèque BluetoothSerial, la carte apparaît sur ton téléphone sous le nom « BlueGrays-RobotKol » et comprend les mêmes commandes. Branche le PCA9685 sur GPIO 21 (SDA) et GPIO 22 (SCL) et alimente VCC en 3V3 ; les signaux des servos sortent alors en 3,3 V, ce que la très grande majorité des servos lit sans problème. BluetoothSerial ne fonctionne que sur l'ESP32 classique (ESP32-WROOM-32, DevKit) ; les ESP32-S2, S3 et C3 ne gèrent pas le Bluetooth classique.
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}Bras robotique avec un Raspberry Pi Pico (MicroPython)
Pour piloter des servos avec le Raspberry Pi Pico, aucune bibliothèque supplémentaire n'est nécessaire : règle le PWM sur 50 Hz et donne la largeur d'impulsion en nanosecondes avec duty_ns(). Avec 16 canaux PWM, le Pico peut piloter 6 servos directement ; les paires de broches d'un même slice partagent la fréquence, mais comme tous les servos utilisent 50 Hz, ce n'est pas un problème. La limite se situe côté analogique : le Pico n'a que trois broches ADC utilisables (GP26, GP27, GP28). C'est pourquoi, dans le code ci-dessous, trois articulations sont pilotées par potentiomètres et la pince s'ouvre et se ferme avec un bouton sur GP14. Le Pico fonctionnant en 3,3 V, branche les potentiomètres sur 3V3 ; les servos restent alimentés par une source externe de 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 loopPour aller plus loin : la cinématique inverse
Jusqu'ici, on a donné l'angle de chaque articulation une par une ; c'est la cinématique directe. La cinématique inverse fait l'inverse : tu indiques le point (x, y) que la pince doit atteindre, et le code calcule les angles nécessaires. Pour un bras à deux segments de longueurs L1 (épaule–coude) et L2 (coude–poignet), on calcule d'abord D = (x² + y² − L1² − L2²) / (2·L1·L2). L'angle du coude vaut θ2 = acos(D) et celui de l'épaule θ1 = atan2(y, x) + atan2(L2·sin θ2, L1 + L2·cos θ2) (solution coude en haut). Par exemple, avec L1 = L2 = 12 cm et un point situé 15 cm devant et 5 cm au-dessus de l'épaule, on obtient D ≈ −0,13, θ2 ≈ 97,6° et θ1 ≈ 67,2° : le bras pointe à 67 degrés au-dessus de l'horizontale et l'avant-bras se plie de 97,6 degrés vers le bas par rapport à lui. Si la valeur absolue de D dépasse 1, le point est hors de portée du bras. L'angle de la base se calcule à part, à partir de la position de la cible vue de dessus. En convertissant les résultats en angles de servo, tiens compte du sens de montage et du point milieu de chaque servo.
Tremblements et resets : erreurs fréquentes et solutions
| Symptôme | Cause probable | Solution |
|---|---|---|
| Les servos tremblent et bourdonnent bras à l'arrêt | Bruit dans les lectures des potentiomètres ou alimentation faible | Ajoute un filtre de lissage et une zone morte de 2°, utilise une alimentation externe et un condensateur de 1000 µF |
| L'Arduino redémarre quand le bras bouge, le HC-05 perd la connexion | Le courant de démarrage des servos fait chuter la tension | Alimente les servos avec une source séparée de 5–6 V, relie les masses, démarre les servos un par un |
| Les servos tressautent à chaque commande Bluetooth | Les interruptions de SoftwareSerial perturbent les impulsions de la bibliothèque Servo | Passe les servos sur un PCA9685 ou utilise le Bluetooth intégré de l'ESP32 |
| À la mise sous tension, le bras bondit brusquement | Les servos ne mémorisent pas leur dernière position et y vont à pleine vitesse à la première commande | Ramène le bras en position de départ avant d'éteindre, appelle write() avant attach() |
| L'épaule ne soulève pas le bras ou s'affaisse lentement | Couple insuffisant | Fais le calcul de couple ; utilise un MG996R, un bras plus court, un contrepoids ou un ressort |
| Une articulation force en bout de course et chauffe | Le servo pousse contre une butée mécanique | Reporte dans le code les limites MIN_A et MAX_A trouvées au calibrage |
| Le servo de la pince chauffe en tenant un objet | La pince continue de vouloir fermer, le servo reste bloqué | Règle l'angle fermé au point où la pince touche tout juste l'objet, ajoute du caoutchouc aux doigts |
| Le PCA9685 est branché mais aucun servo ne bouge | Pas de tension sur le bornier V+ ou pas de masse commune | Alimente V+ en 5–6 V et vérifie l'adresse I2C (0x40) |
| Une articulation patine sous charge | Le palonnier en plastique a perdu ses cannelures ou la vis centrale manque | Utilise un palonnier métallique et fixe-le sur l'axe avec la vis centrale |
Idées de projets avec un bras robotique
- Bras trieur de couleurs : Lis la couleur de cubes avec un capteur de couleur TCS3200 et laisse le bras déposer chaque couleur dans sa boîte.
- Contrôle par gestes : Avec un MPU6050 fixé sur un gant, le bras robotique s'incline comme ton poignet.
- Télécommande sans fil : Branche deux joysticks sur un second Arduino et envoie les commandes avec un nRF24L01 ; tu obtiens une télécommande qui se passe du téléphone.
- Contrôle depuis le navigateur : Crée des curseurs sur une page web avec un ESP32 et pilote le bras depuis n'importe quel appareil du même réseau Wi-Fi ; un WebSocket sur ESP32 réduit la latence au minimum.
- Saisie sur tapis roulant : Fabrique un petit convoyeur avec un moteur pas à pas ; quand un TCRT5000 détecte un objet, le bras le retire du tapis.
- Concours et projet scolaire : Un bras qui enregistre et rejoue ses mouvements est un excellent choix parmi les idées de projets pour concours scientifiques, car il montre mécanique, électronique et logiciel à la fois.
Un bras robotique Arduino t'apprend en même temps la conception mécanique, le calcul du couple, la gestion de l'alimentation et la programmation de mouvements fluides, et il grandit avec chaque heure que tu y consacres. Commence par un bras à 4 servos piloté par potentiomètres, ajoute l'enregistrement et la lecture, puis passe à 6 servos avec un PCA9685 et le Bluetooth. Dans l'application BlueGrays, tu trouveras des projets comme le contrôle de servo par potentiomètre et par joystick, le pilotage Bluetooth depuis le téléphone et une chorégraphie à 32 servos, avec schémas de câblage et code pas à pas, pour tester d'abord chaque articulation de ton bras séparément.
Questions fréquentes
Quel servomoteur choisir pour un bras robotique Arduino ?
Pour les articulations porteuses comme la base, l'épaule et le coude, le MG996R à pignons métalliques et 9–11 kg·cm de couple est un bon choix. Pour les articulations légères comme le poignet et la pince, un MG90S ou un SG90 suffit. Les petits bras équipés uniquement de SG90 fonctionnent s'ils restent courts et légers, mais ne soulèvent que des objets de quelques dizaines de grammes.
Quelle alimentation faut-il pour un bras robotique ?
Pour un petit bras à 4 servos SG90 ou MG90S, un bloc 5 V 3 A suffit. Pour un bras à 6 servos avec 3 MG996R et 3 petits servos, prévois une alimentation à découpage 5–6 V d'au moins 5 A, ou 10 A pour avoir de la marge. N'oublie pas de relier le moins de l'alimentation au GND de l'Arduino.
Combien de servos peut-on brancher sur un Arduino ?
La bibliothèque Servo gère jusqu'à 12 servos sur l'Arduino Uno et 48 sur le Mega. La vraie limite reste le courant : tous les servos doivent être alimentés par une source externe. Un module PCA9685 pilote 16 servos avec seulement deux broches I2C et peut être chaîné jusqu'à 62 modules.
Pourquoi les servos de mon bras robotique tremblent-ils ?
Les causes les plus fréquentes sont une alimentation insuffisante, l'absence de masse commune et le bruit dans les lectures des potentiomètres. Utilise une alimentation externe avec un condensateur de 1000 µF sur la ligne des servos, et ajoute dans le code un filtre de lissage et une zone morte. Si SoftwareSerial et la bibliothèque Servo sont utilisés ensemble, passer les servos sur un PCA9685 supprime complètement les tremblements.
Quel poids peut soulever un bras robotique à SG90 ?
Le couple de blocage du SG90 est d'environ 1,8 kg·cm ; pour un fonctionnement sûr, compte la moitié, soit 0,9 kg·cm. Comme le poids du bras et des servos consomme déjà une partie de ce budget, un bras à SG90 d'une quinzaine de centimètres ne porte en pratique que des objets légers de 20–30 g, comme un bouchon de bouteille ou un petit cube de mousse.
Comment piloter un bras robotique depuis son téléphone ?
On branche un module Bluetooth HC-05 sur l'Arduino, puis un terminal série Bluetooth ou une application de contrôle à curseurs envoie des commandes texte comme « S120 ». Avec un ESP32, le Bluetooth intégré évite d'ajouter un module. Le HC-05 ne fonctionne pas avec l'iPhone ; pour un iPhone, il faut un module BLE ou l'ESP32 BLE.
Projets à réaliser après cet article
Voir tous les projets
Utilisation d'un servomoteur avec un potentiomètre
Quand tu tournes le bouton du potentiomètre, le bras du servomoteur tourne avec lui : un bout du bouton correspond à zéro degré, l'autre à un demi-tour. L'Arduino lit sans arrêt la position du bouton,

Servocommande avec joystick
Pilote deux moteurs avec un joystick, comme si tu orientais une caméra de surveillance. Pousse le manche à gauche ou à droite et le servomoteur du bas tourne doucement, vers le haut ou le bas et celui

Utilisation du servomoteur
Le bras d'un petit servomoteur tourne tour à tour vers trois positions : tout au début, pile au milieu et tout au bout, en attendant deux secondes à chaque arrêt. L'Arduino indique au moteur l'angle à

Servomoteur ESP32 (commande par potentiomètre)
Dans ce projet, nous contrôlons un servomoteur SG90 à l'aide d'un potentiomètre. Nous réglons l'angle du servomoteur en mappant la valeur analogique lue par le potentiomètre sur une plage de 0 à 180 degrés. La bibliothèque ESP32Servo génère des signaux de servomoteur sur les GPIO appropriés de l'ESP32 pouvant fonctionner en sortie ; ce projet utilise GPIO 18. Il s'agit d'une méthode de contrôle fondamentale pour les bras robotiques, les cardans de caméra et les mécanismes de portes automatiques.

Contrôler une LED depuis un téléphone via Bluetooth
Une petite répétition pour allumer et éteindre les lumières de ta chambre depuis ton téléphone. Le module Bluetooth transmet à l'Arduino les lettres envoyées par ton téléphone ; une lettre allume la L

Voiture contrôlée par Bluetooth avec L298N
Transforme ton téléphone en télécommande et pilote ta propre voiture robot. L'Arduino reçoit, via un module Bluetooth, les ordres d'une appli de télécommande sur ton téléphone et fait tourner les roue

Chorégraphie de servos en cercle - Motifs animés avec 32 servos
Un projet d'animation visuelle utilisant 32 servomoteurs disposés en cercle sur un Arduino Mega. Les servos sont gérés en un seul réseau et connectés aux broches 22-53 du Mega pour afficher quatre séquences de mouvement différentes : une vibration chaotique où tous les servos se déplacent à des angles aléatoires, un balayage synchrone où ils se déplacent tous en même temps, une vague tournant doucement autour d'un cercle, et enfin une aiguille de boussole se balançant à gauche et à droite. L'eff
Autres articles
Application BlueGrays
Réalise ce montage pas à pas sur ton téléphone
Schéma, code et liste des composants sur un seul écran. Plus de 200 projets Arduino, ESP32 et Pico à réaliser.
Scanne avec ton téléphone
Pointe l’appareil photo vers le code : la boutique d’applications de ton téléphone s’ouvre.
ou ouvre la boutique

