Exemple:1 EEZYbotArm MK3 (Boutons + Potentiomètre + Servo SG90 + 28BYJ-48 + ULN2003 + PCA9685 + Arduino Uno)
Description :
Ce projet est une plateforme de contrôle basée sur Arduino, conçue pour piloter simultanément trois moteurs pas à pas et un servomoteur à l’aide d’une interface utilisateur simple et d’un expandeur de broches PWM (PCA9685).
L’objectif est de démontrer le contrôle précis de multiples actionneurs (moteurs) en utilisant une seule carte Arduino, en déléguant la gestion des signaux de moteur pas à pas et PWM à un circuit intégré dédié. Le système permet de définir la direction et la vitesse des trois moteurs pas à pas, et de contrôler la position du servomoteur.
Prérequis :
- 1 x Carte Arduino Uno
- 3 x 28BYJ-48
- 3 x ULN2003
- 7 x Boutons
- 1 x Potentiomètre 10KΩ
- 1 x Carte PCA9685
- 1 x Servo numérique Sg90
- 1 x Breadboard
- 1 x Alimentation 12V
- Fils de connexion
Version IDE :
- Arduino IDE 2.3.5
Bibliothèque :
- Stepper.h
- Adafruit BusIO (version: 1.17.2 par Adafruit)
- Adafruit-PWM-Servo-Driver-Library-master (version: 3.0.2 par Adafruit)
STL :
Vidéo de démonstration :
NA
Schéma de câblage :


// Définition des broches numériques de l'Arduino connectées aux 7 boutons.
const int BoutonRouge = 8;
const int BoutonVert = 7;
const int BoutonJaune = 6;
const int BoutonBlanc = 5;
const int BoutonBleue = 4;
const int BoutonRouge2 = 3;
const int BoutonVert2 = 2;
// Variable pour stocker le délai (vitesse) entre chaque pas du moteur.
long stepDelay;
// Inclusion de la bibliothèque pour le contrôle du servomoteur.
#include <Servo.h>
Servo myservo;
// Modes de fonctionnement possibles pour les moteurs pas à pas.
// ModeMoteur = 1 = Séquence en demi-pas (8 pas, couple modéré/meilleure résolution)
// ModeMoteur = 2 = Séquence en pas simple unipolaire (4 pas)
// ModeMoteur = 3 = Séquence en pas double unipolaire (4 pas, maximum de force)
int ModeMoteur = 3;
// Inclusion de la bibliothèque pour le driver de servomoteur/PWM I2C (PCA9685).
#include <Adafruit_PWMServoDriver.h>
// Créer l'objet PCA9685. L'adresse par défaut est 0x40.
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// Définitions des canaux (broches de sortie) du PCA9685 connectées aux ULN2003
// Moteur 1 (M1)
#define IN1_PIN_M1 0
#define IN2_PIN_M1 1
#define IN3_PIN_M1 2
#define IN4_PIN_M1 3
// Moteur 2 (M2)
#define IN1_PIN_M2 4
#define IN2_PIN_M2 5
#define IN3_PIN_M2 6
#define IN4_PIN_M2 7
// Moteur 3 (M3)
#define IN1_PIN_M3 8
#define IN2_PIN_M3 9
#define IN3_PIN_M3 10
#define IN4_PIN_M3 11
// Broche de l'Arduino connectée au servomoteur (Broche 9 PWM par défaut)
#define SERVO_PIN 9
// Broche analogique de l'Arduino connectée au potentiomètre (pour le contrôle de la vitesse)
const int potarPin = A0;
// Séquence pour le moteur 28BYJ-48 (pour le mode demi-pas, 8 étapes)
// Les valeurs 4095 (HIGH) et 0 (LOW) correspondent à l'état ON/OFF des bobines.
const int StepSequence[9][4] = {
{ 4095, 0, 0, 0 }, // Étape 0: IN1 HIGH (Unipolar Half-Step 1)
{ 4095, 4095, 0, 0 }, // Étape 1: IN1 & IN2 HIGH (Unipolar Double-Step 1)
{ 0, 4095, 0, 0 }, // Étape 2: IN2 HIGH
{ 0, 4095, 4095, 0 }, // Étape 3: IN2 & IN3 HIGH
{ 0, 0, 4095, 0 }, // Étape 4: IN3 HIGH
{ 0, 0, 4095, 4095 }, // Étape 5: IN3 & IN4 HIGH
{ 0, 0, 0, 4095 }, // Étape 6: IN4 HIGH
{ 4095, 0, 0, 4095 }, // Étape 7: IN4 & IN1 HIGH
{ 0, 0, 0, 0 } // Étape 8: Bobines éteintes (pour l'arrêt)
};
void setup() {
Serial.begin(9600);
// Configure toutes les broches des boutons en INPUT_PULLUP.
// La résistance pull-up interne est activée, l'entrée est HIGH par défaut.
// Le bouton pressé tire la broche à LOW.
pinMode(BoutonRouge, INPUT_PULLUP);
pinMode(BoutonVert, INPUT_PULLUP);
pinMode(BoutonJaune, INPUT_PULLUP);
pinMode(BoutonBlanc, INPUT_PULLUP);
pinMode(BoutonBleue, INPUT_PULLUP);
pinMode(BoutonRouge2, INPUT_PULLUP);
pinMode(BoutonVert2, INPUT_PULLUP);
// Initialise le module PCA9685.
pwm.begin();
myservo.attach(SERVO_PIN);
}
void loop() {
// Lit la valeur analogique du potentiomètre (0 à 1023).
int potarValue = analogRead(potarPin);
// Mappe la valeur du potentiomètre à un délai en microsecondes (pour le contrôle de la vitesse).
// potar=0 (lent, délai=8000µs) -> potar=1023 (rapide, délai=0µs).
// Un délai de 0µs est cependant problématique et sera limité par la vitesse d'exécution de loop().
stepDelay = map(potarValue, 0, 1023, 8000, 0);
// --- Contrôle du Moteur 1 (M1) ---
if (digitalRead(BoutonRouge) == LOW) { // Si BoutonRouge est pressé
Step_M1(1, stepDelay); // Fait avancer le M1 (Direction 1)
} else if (digitalRead(BoutonVert) == LOW) { // Si BoutonVert est pressé
Step_M1(2, stepDelay); // Fait reculer le M1 (Direction 2)
} else {
Step_M1(0, 0); // Arrête le M1 (Direction 0: désactive les bobines)
}
// --- Contrôle du Moteur 2 (M2) ---
if (digitalRead(BoutonJaune) == LOW) {
Step_M2(1, stepDelay); // M2 Avance
} else if (digitalRead(BoutonBlanc) == LOW) {
Step_M2(2, stepDelay); // M2 Recule
} else {
Step_M2(0, 0); // M2 Arrêt
}
// --- Contrôle du Moteur 3 (M3) ---
if (digitalRead(BoutonBleue) == LOW) {
Step_M3(2, stepDelay); // M3 Recule (ordre des directions inversé par rapport à M1/M2)
} else if (digitalRead(BoutonRouge2) == LOW) {
Step_M3(1, stepDelay); // M3 Avance
} else {
Step_M3(0, 0); // M3 Arrêt
}
// --- Contrôle du Servomoteur ---
if (digitalRead(BoutonVert2) == LOW) { // Si BoutonVert2 est pressé
myservo.write(10); // Définit l'angle du servo à 10 degrés
} else {
myservo.write(80); // Définit l'angle du servo à 80 degrés (position par défaut/repos)
}
}
// Fait avancer le moteur pas à pas 1 d'une ou plusieurs étapes.
// 'direction_M1': 1=Avance, 2=Recule, 0=Arrêt.
// 'motorspeed_M1': Délai en microsecondes entre les étapes (contrôle de la vitesse).
void Step_M1(int direction_M1, long motorspeed_M1) {
int sequence_M1;
// Variable statique pour conserver l'état de l'étape du moteur entre les appels de fonction.
static int step_M1 = 0;
// Détermine la taille du pas (le nombre de pas à sauter dans la séquence StepSequence).
if (ModeMoteur == 1 || ModeMoteur == 2) {
// Mode 1 (demi-pas) ou Mode 2 (pas simple) -> sequence_M1 = 1 ou 2.
sequence_M1 = ModeMoteur;
}
if (ModeMoteur == 3) { // Mode 3 (double-pas/force maximale)
sequence_M1 = ModeMoteur - 1; // sequence_M1 = 2 (saut de 2 dans la séquence 8 pas)
if (step_M1 == 0) {
step_M1 = 1; // Si l'étape est 0 (position d'arrêt), force à l'étape 1 pour démarrer en mode double-pas.
}
}
// Applique l'état actuel des bobines (StepSequence[step_M1]) via le PCA9685.
// La fonction setPWM(channel, on_tick, off_tick) est utilisée pour définir la sortie ON/OFF.
// 'on_tick' est toujours 0, 'off_tick' est 4095 (ON) ou 0 (OFF).
pwm.setPWM(IN1_PIN_M1, 0, StepSequence[step_M1][0]);
pwm.setPWM(IN2_PIN_M1, 0, StepSequence[step_M1][1]);
pwm.setPWM(IN3_PIN_M1, 0, StepSequence[step_M1][2]);
pwm.setPWM(IN4_PIN_M1, 0, StepSequence[step_M1][3]);
// Mise à jour de l'étape pour le prochain appel (selon la direction).
if (direction_M1 == 1) { // Avance
// Ajoute sequence_M1 et utilise le modulo 8 pour boucler de 0 à 7.
step_M1 = (step_M1 + sequence_M1) % 8;
} else if (direction_M1 == 2) { // Recule
// Soustrait sequence_M1 et ajoute 8 avant le modulo pour gérer les résultats négatifs correctement.
step_M1 = (step_M1 - sequence_M1 + 8) % 8;
} else { // Arrêt (direction_M1 == 0)
step_M1 = 8; // Définit l'étape sur 8 (bobines éteintes, voir StepSequence[8])
}
// Attend le délai spécifié (vitesse).
delayMicroseconds(motorspeed_M1);
}
void Step_M2(int direction_M2, long motorspeed_M2) {
int sequence_M2;
static int step_M2 = 0;
if (ModeMoteur == 1 || ModeMoteur == 2) {
sequence_M2 = ModeMoteur;
}
if (ModeMoteur == 3) {
sequence_M2 = ModeMoteur - 1;
if (step_M2 == 0) {
step_M2 = 1;
}
}
pwm.setPWM(IN1_PIN_M2, 0, StepSequence[step_M2][0]);
pwm.setPWM(IN2_PIN_M2, 0, StepSequence[step_M2][1]);
pwm.setPWM(IN3_PIN_M2, 0, StepSequence[step_M2][2]);
pwm.setPWM(IN4_PIN_M2, 0, StepSequence[step_M2][3]);
if (direction_M2 == 1) {
step_M2 = (step_M2 + sequence_M2) % 8;
} else if (direction_M2 == 2) {
step_M2 = (step_M2 - sequence_M2 + 8) % 8;
} else {
step_M2 = 8;
}
delayMicroseconds(motorspeed_M2);
}
void Step_M3(int direction_M3, long motorspeed_M3) {
int sequence_M3;
static int step_M3 = 0;
if (ModeMoteur == 1 || ModeMoteur == 2) {
sequence_M3 = ModeMoteur;
}
if (ModeMoteur == 3) {
sequence_M3 = ModeMoteur - 1;
if (step_M3 == 0) {
step_M3 = 1;
}
}
pwm.setPWM(IN1_PIN_M3, 0, StepSequence[step_M3][0]);
pwm.setPWM(IN2_PIN_M3, 0, StepSequence[step_M3][1]);
pwm.setPWM(IN3_PIN_M3, 0, StepSequence[step_M3][2]);
pwm.setPWM(IN4_PIN_M3, 0, StepSequence[step_M3][3]);
if (direction_M3 == 1) {
step_M3 = (step_M3 + sequence_M3) % 8;
} else if (direction_M3 == 2) {
step_M3 = (step_M3 - sequence_M3 + 8) % 8;
} else {
step_M3 = 8;
}
delayMicroseconds(motorspeed_M3);
}
