Je travaille sur un projet réunissant un moteur pas à pas Nema 17 piloté par un A4988, une ESP32 AZDelivery NodeMCU32, et un anneau de 24 LED. J'ai un souci de mouvement involontaire.
La situation est la suivante : lors de la calibration, le moteur tourne dans le sens antihoraire jusqu’à la détection par un fin de course, puis il poursuit sa course de 850 pas à partir de cette détection, ce qui définit son point zéro. Suite à cette prise de référence, le moteur se positionne directement en position 1 (1200 pas), sans qu'aucun ordre n'ait été donné.
Son cycle normal est le suivant : Déplacement 1 (1120 pas), Déplacement 2 (2500 pas), Déplacement 3 (4000 pas), suivi d'un dernier déplacement de retour au point zéro. Le problème est que le moteur se positionne systématiquement à 25 % après la prise de référence ou après le retour à cette référence.
J'ai questionné l'IA et testé plusieurs configurations, mais rien n'y fait. À part que mes cheveux tombent, en plus de mes bras, je n'arrive pas à comprendre ce qui ne fonctionne pas dans mon code. Une bonne âme serait-elle disposée à aider un pauvre débutant comme moi ?
Je vous joins le code ci-dessous. Juste une petite précision : j'utilise le logiciel Arduino sur un Mac avec macOS 10.12.6, ce qui explique certaines bibliothèques qui datent un peu, mais je ne crois pas que cela ait une influence sur le problème que je rencontre.
Je serais ravi de vous lire, dans l'espoir que tous mes cheveux ne tombent pas complètement…
#include <WiFi.h>
#include <WebServer.h>
#include <AccelStepper.h>
#include <FastLED.h>
// Informations de connexion WiFi
const char* ssid = "xxxxxxxxxx"; // Remplacez par votre SSID
const char* password = "xxxxxxxxxx"; // Remplacez par votre mot de passe
// Définition des broches pour le moteur pas à pas, le bouton poussoir, le capteur de point zéro, et l'A4988 enable pin
#define dirPin 12
#define stepPin 13
#define buttonPin 14
#define enablePin 27 // Pin d'activation du moteur
#define zeroPointPin 26 // Broche pour le capteur de point zéro
// Définition des broches et paramètres pour les LEDs
#define LED_PIN 33
#define NUM_LEDS 24
CRGB leds[NUM_LEDS];
// Définir les broches tactiles
#define touchPin1 02 // Utiliser la broche tactile T3 pour commande moteur (GPIO 2)
#define touchPin2 15 // Utiliser la broche tactile T9 pour commande couleurs (GPIO 15)
// Créer une instance de serveur web
WebServer server(80);
// Créer une instance de la classe AccelStepper
AccelStepper stepper(AccelStepper::DRIVER, stepPin, dirPin);
// Variables pour les positions du moteur
int positions[3] = {1200, 2500, 4000}; // Trois positions intermédiaires
int buttonPressCount = 0; // Compteur d'appuis du bouton
bool motorActive = false; // Indique si le moteur est actif
bool calibrationComplete = false; // Indique si la calibration est terminée
// Seuil de détection tactile
int touchThreshold = 45; // Augmenter cette valeur pour réduire la sensibilité
// Variables pour le délai anti-rebond
unsigned long lastTouchTime = 0;
unsigned long debounceDelay = 200; // Délai anti-rebond de 200ms
// Fonction de détection du point zéro
bool isZeroPoint() {
return digitalRead(zeroPointPin) == HIGH; // Ajustez selon votre capteur
}
// Fonction pour calibrer le point zéro
void calibrateZeroPoint() {
Serial.println("Début de la calibration du point zéro.");
motorActive = true; // Le moteur est actif
digitalWrite(enablePin, LOW); // Activer le moteur
stepper.setMaxSpeed(4000);
stepper.setAcceleration(4000);
stepper.setSpeed(-2000); // Déplacement vers le capteur
// Faire tourner le moteur jusqu'à ce que le point zéro soit détecté
while (!isZeroPoint()) {
stepper.runSpeed();
Serial.println("Moteur en mouvement...");
}
// Stopper le moteur dès que le point zéro est détecté
stepper.stop(); // Assure l'arrêt immédiat du moteur
delay(10); // Petite pause pour garantir l'arrêt complet
Serial.println("Point zéro détecté, mouvement en arrière...");
// Ajustement de la vitesse et de l'accélération pour le mouvement arrière
stepper.setMaxSpeed(2000); // Réduire la vitesse pour plus de précision
stepper.setAcceleration(1000); // Ajuster l'accélération
stepper.move(-850); // Mouvement de 850 pas en arrière
stepper.runToPosition(); // Exécuter jusqu'à la position cible
stepper.setCurrentPosition(0); // Définir la position actuelle comme le point zéro
Serial.println("Point zéro atteint et position calibrée.");
calibrationComplete = true;
motorActive = false;
digitalWrite(enablePin, HIGH); // Désactiver le moteur
}
// Fonction pour l'effet chenillard
void showStartupSequence() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CHSV(i * 255 / NUM_LEDS, 255, 255); // Couleurs arc-en-ciel
FastLED.show();
delay(50);
}
delay(500);
FastLED.clear();
FastLED.show();
}
// Fonction pour ajuster la luminosité des LEDs
void setLEDBrightness(uint8_t brightness) {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB::White;
}
FastLED.setBrightness(brightness);
FastLED.show();
}
// Définir les couleurs des LEDs
void setLEDColor(CRGB color) {
fill_solid(leds, NUM_LEDS, color);
FastLED.show();
}
// Éteindre les LEDs
void turnOffLEDs() {
FastLED.clear();
FastLED.show();
}
void setup() {
Serial.begin(115200);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(enablePin, OUTPUT);
pinMode(zeroPointPin, INPUT_PULLUP);
// Initialiser les LEDs
FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
// Montrer l'effet chenillard au démarrage
showStartupSequence();
calibrateZeroPoint(); // Calibration au démarrage
stepper.setMaxSpeed(4000);
stepper.setAcceleration(10000);
// Connexion au Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connexion au WiFi en cours...");
}
Serial.println("Connecté au réseau WiFi.");
server.on("/", handleRoot);
server.on("/position1", handlePosition1);
server.on("/position2", handlePosition2);
server.on("/position3", handlePosition3);
server.on("/return_to_zero", handleReturnToZero);
server.on("/move_5000", handleMove5000); // Nouvelle route pour le mouvement de 5000 pas
server.on("/led_blue", handleBlueLEDs); // Route pour définir les LEDs en bleu
server.on("/led_pink", handlePinkLEDs); // Route pour définir les LEDs en rose
server.on("/led_orange", handleOrangeLEDs); // Route pour définir les LEDs en orange
server.on("/led_off", handleOffLEDs); // Route pour éteindre les LEDs
server.begin();
Serial.println("Serveur web démarré.");
}
void loop() {
server.handleClient();
static int lastButtonState = HIGH;
int buttonState = digitalRead(buttonPin);
// Lire les valeurs tactiles
int touchValue1 = touchRead(touchPin1);
int touchValue2 = touchRead(touchPin2);
// Moyennage des lectures tactiles
static int touchSum1 = 0;
static int touchSum2 = 0;
static int touchCount = 0;
const int numReadings = 10; // Nombre de lectures pour la moyenne
touchSum1 += touchValue1;
touchSum2 += touchValue2;
touchCount++;
if (touchCount >= numReadings) {
int touchAverage1 = touchSum1 / numReadings;
int touchAverage2 = touchSum2 / numReadings;
touchSum1 = 0;
touchSum2 = 0;
touchCount = 0;
// Vérifier si le fil de cuivre est touché pour le moteur
if (touchAverage1 < touchThreshold && calibrationComplete) {
delay(50);
buttonPressCount = (buttonPressCount + 1) % 4;
if (buttonPressCount == 1) {
moveToPosition(positions[0]);
setLEDBrightness(64); // 25% de luminosité
} else if (buttonPressCount == 2) {
moveToPosition(positions[1]);
setLEDBrightness(128); // 50% de luminosité
} else if (buttonPressCount == 3) {
moveToPosition(positions[2]);
setLEDBrightness(255); // 100% de luminosité
} else {
moveToPosition(0);
FastLED.clear(); // Éteindre les LEDs
FastLED.show();
}
}
// Vérifier si le fil de cuivre est touché pour les LEDs
if (touchAverage2 < touchThreshold) {
unsigned long currentMillis = millis();
if (currentMillis - lastTouchTime >= debounceDelay) {
lastTouchTime = currentMillis; // Mettre à jour le temps du dernier contact
static int ledState = 0;
ledState = (ledState + 1) % 4; // Alterne entre 0, 1, 2, 3
if (ledState == 0) {
setLEDColor(CRGB::Blue);
} else if (ledState == 1) {
setLEDColor(CRGB::DeepPink);
} else if (ledState == 2) {
setLEDColor(CRGB::Orange);
} else if (ledState == 3) {
turnOffLEDs();
}
}
}
}
if (buttonState == LOW && lastButtonState == HIGH) {
buttonPressCount = (buttonPressCount + 1) % 4;
if (buttonPressCount == 1) {
moveToPosition(positions[0]);
setLEDBrightness(64);
} else if (buttonPressCount == 2) {
moveToPosition(positions[1]);
setLEDBrightness(128);
} else if (buttonPressCount == 3) {
moveToPosition(positions[2]);
setLEDBrightness(255);
} else {
moveToPosition(0);
FastLED.clear();
FastLED.show();
}
}
lastButtonState = buttonState;
}
void handleRoot() {
String html = "\
<html>\
<head>\
<title>Contrôle du moteur et des LEDs</title>\
<style>\
body { font-family: Arial, sans-serif; text-align: center; padding: 10px; background-color: #f0f0f0; }\
h1 { color: #333; margin-bottom: 50px; }\
.container { display: flex; justify-content: center; align-items: center; flex-wrap: wrap; }\
.column { flex-basis: 48%; margin: 10px; }\
.left, .right { flex-basis: 48%; }\
button { width: 80%; padding: 40px; font-size: 48px; margin-bottom: 10px; border: none; border-radius: 10px; cursor: pointer; }\
.left button { background-color: #4CAF50; color: white; }\
.right button.blue { background-color: blue; color: white; }\
.right button.pink { background-color: pink; color: white; }\
.right button.orange { background-color: orange; color: white; }\
.right button.off { background-color: grey; color: white; }\
</style>\
<script>\
function sendRequest(url) {\
var xhttp = new XMLHttpRequest();\
xhttp.open('GET', url, true);\
xhttp.send();\
}\
</script>\
</head>\
<body>\
<div class=\"container\">\
<div class=\"column left\">\
<h1>Moteur</h1>\
<button onclick=\"sendRequest('/position1')\">25%</button><br>\
<button onclick=\"sendRequest('/position2')\">50%</button><br>\
<button onclick=\"sendRequest('/position3')\">100%</button><br>\
<button onclick=\"sendRequest('/return_to_zero')\">Off</button><br>\
<button onclick=\"sendRequest('/move_5000')\">Démontage</button><br>\
</div>\
<div class=\"column right\">\
<h1>LEDs</h1>\
<button class=\"blue\" onclick=\"sendRequest('/led_blue')\">Bleu</button><br>\
<button class=\"pink\" onclick=\"sendRequest('/led_pink')\">Rose</button><br>\
<button class=\"orange\" onclick=\"sendRequest('/led_orange')\">Orange</button><br>\
<button class=\"off\" onclick=\"sendRequest('/led_off')\">Éteindre</button><br>\
</div>\
</div>\
</body>\
</html>";
server.send(200, "text/html", html);
}
void handlePosition1() {
moveToPosition(positions[0]);
server.send(200, "text/html", "Déplacé à la position 1");
}
void handlePosition2() {
moveToPosition(positions[1]);
server.send(200, "text/html", "Déplacé à la position 2");
}
void handlePosition3() {
moveToPosition(positions[2]);
server.send(200, "text/html", "Déplacé à la position 3");
}
void handleReturnToZero() {
moveToPosition(0);
server.send(200, "text/html", "Retour au point zéro");
}
void handleMove5000() {
moveToPosition(5000);
server.send(200, "text/html", "Déplacé de 5000 pas");
}
void handleBlueLEDs() {
setLEDColor(CRGB::Blue);
server.send(200, "text/html", "LEDs bleues activées");
}
void handlePinkLEDs() {
setLEDColor(CRGB::DeepPink);
server.send(200, "text/html", "LEDs roses activées");
}
void handleOrangeLEDs() {
setLEDColor(CRGB::Orange);
server.send(200, "text/html", "LEDs oranges activées");
}
void handleOffLEDs() {
turnOffLEDs();
server.send(200, "text/html", "LEDs éteintes");
}
void moveToPosition(int position) {
if (!motorActive && calibrationComplete) {
motorActive = true;
digitalWrite(enablePin, LOW);
stepper.moveTo(position);
stepper.runToPosition();
motorActive = false;
digitalWrite(enablePin, HIGH);
}
}