C'est marrant, quelqu'un m'a posé la question sur YT ...
Je pense que ça doit être possible mais avec 3 moteurs et un bon parallélisme dans tous les plans sera plus difficile à obtenir, mais ça ne me paraît pas infaisable.
C'est marrant, quelqu'un m'a posé la question sur YT ...
+1 même si je n'y comprends pas grand choseC2Vues-BricoTrain a écrit : ↑25 juin 2025, 17:04 Bonjour Patrick,
Je suis toujours stupéfait de ce que tu réalises, et le résultat est toujours tellement "PRO" !![]()
![]()
![]()
![]()
![]()
![]()
Amicalement.
Fernando
Code : Tout sélectionner
/* Commande Ascenseur Nema 17 avec TMC2209 et Arduino Uno
Les deux moteurs sont en parallèle sur les mêmes broches
********************************************************
Version 1.10 © Ramasoft Juin 2025
********************************************************
Brochage Prise RJ45-1 vers ascenseur
1 -> +5V
2 -> 0V Gnd
3 -> Relais DCC pont
4 -> Capteur IR
5 -> Inutilisée
6 -> DIR_PIN (jaune)
7 -> STEP_PIN (rouge)
8 -> EN_PIN (bleu)
Masse -> non connectée
Brochage Prise RJ45-2 vers carte relais DCC
1 -> +5V
2 -> 0V Gnd
3 -> Relais DCC Voie Niveau - 1
4 -> Relais DCC Voie Niveau - 2
5 -> Relais DCC Voie Niveau - 3
6 -> Relais DCC Voie Niveau - 4
7 -> Inutilisée
8 -> Inutilisée
Masse -> non connectée
************************************************************
Broches Utilisées sur l'Arduino
************************************************************
Broches de contrôle des Moteurs
2 -> ENABLE -> RJ45-1 Broche 8
3 -> STEP -> RJ45-1 Broche 7
4 -> DIR -> RJ45-1 Broche 6
Autres Broches utilisées
5 -> IR_PIN 5 -> RJ45-1 Broche 4 Capteur IR détection fin de course
6 -> DCC_PIN 6 -> RJ45-1 Broche 3 Relais du DCC sur le pont
Boutons de commande
7 -> CLK_PIN Encodeur CLOCK
8 -> DT_PIN Encodeur DATA
9 -> SW_PIN Encodeur Switch
10 -> BoutonHaut Bouton Haut
11 -> BoutonBas Bouton Bas
12 -> BoutonHaut_R Bouton Haut Rapide
13 -> BoutonBas_R Bouton Bas Rapide
(9 -> BoutonMemo Bouton Mémorisation -> partage broche avec SW_PIN)
Écran LCD LiquidCrystal I2C : A4 -> SDA A5 -> SCL
Broches pour les relais qui mettent le DCC sur les voies de stockage
14 -> RJ45-2 broche 3 Relais DCC voie niveau -1 -> correspond à A0
15 -> RJ45-2 broche 4 Relais DCC voie niveau -2 -> correspond à A1
16 -> RJ45-2 broche 5 Relais DCC voie niveau -3 -> correspond à A2
17 -> RJ45-2 broche 6 Relais DCC voie niveau -4 -> correspond à A3
*/
//********************
// Déclarations
#include <AccelStepper.h> // Bibliothéque Moteur pas a pas
#include <LiquidCrystal_I2C.h> // Bibliothèque pour l'écran LCD
#include <EEPROM.h> // Bibliothèque pour accéder à l'EEPROM
// Broches de contrôle des Moteurs
#define EN_PIN 2 //Bleu Enable
#define STEP_PIN 3 //Rouge Step
#define DIR_PIN 4 //Jaune Dir
// Autres Broches utilisées
#define IR_PIN 5 //Capteur IR détection fin de course haut
#define DCC_PIN 6 //Relais du DCC sur le pont
// Boutons de commande
#define CLK_PIN 7 // Encodeur CLOCK
#define DT_PIN 8 // Encodeur DATA
#define SW_PIN 9 // Encodeur SWITCH
#define BoutonHaut 10 // Bouton Haut
#define BoutonBas 11 // Bouton Bas
#define BoutonHaut_R 12 // Bouton Haut Rapide
#define BoutonBas_R 13 // Bouton Bas Rapide
// // Bouton Mémorisation -> partage la broche 9 avec SW_PIN
AccelStepper Moteur(AccelStepper:: DRIVER, STEP_PIN, DIR_PIN); // création de l'objet Moteur
LiquidCrystal_I2C lcd(0x27, 20, 4); // création de l'objet lcd
// Encodeur rotatif
const int pinCLK = 7;
const int pinDT = 8;
const int pinSW = 9;
bool lastCLK = HIGH;
// Menus
const int MAIN_MENU = 0;
const int Menu_Reglage = 2;
int currentMenuLevel = MAIN_MENU;
int currentMenuIndex = 0;
int topMenuIndex = 0;
// Menu principal
const int mainMenuLength = 6;
String mainMenu[mainMenuLength] = {
"Niveau 0 Choix ->",
"1e Sous-Sol",
"2e Sous-Sol",
"3e Sous-Sol",
"4e Sous-sol",
"Memorisation"
};
String* activeMenu;
int activeMenuLength;
// Crans Moteur pour les différents niveaux par défaut
unsigned long tableauPositions [] = {0, 10000, 20000, 40000, 50000};
int8_t Niveau = -1; // Niveau actuel: -1 = indéfini
// Autres paramètres
const float VMax = 4000; // Vitesse maxi des moteurs
const float Acceleration = 500; // Distance pour Accélération et Décelération
const float HOMING_SPEED = -2000; // Vitesse pendant le homing -> négative pour monter
const float HOMING_MAXSPEED = 1200; // Vitesse maxi pour Homing
int VitesseLente = 500; // Paramètres de vitesse
int VitesseRapide = 2000; // pour réglages
long DistanceDeplacement = 50; // Déplacement relatif
// Configuration pour EEPROM
const int EEPROM_MAGIC_ADDR = 0; // Adresse pour le flag magique
const int EEPROM_DATA_ADDR = 4; // Adresse pour les données (juste après le flag)
const unsigned long MAGIC_FLAG = 0xDEADBEEF; // le flag qui permet de s'assurer que les données existent bien dans l'EEPROM
// Fin des déclarations
//*********************
void setup()
{
lcd.init();
lcd.backlight();
afficherProgressivement(1, " Le petit train ");
afficherProgressivement(2, " du Berry ");
afficherProgressivement(3, " (c) RAMASOFT 2025 ");
pinMode(pinCLK, INPUT_PULLUP); // Broche de l'encodeur rotatif CLK
pinMode(pinDT, INPUT_PULLUP); // Broche de l'encodeur rotatif DATA
pinMode(pinSW, INPUT_PULLUP); // Contact click de l'encodeur SWITCH
pinMode(IR_PIN,INPUT); // Le capteur IR passe à LOW quand l'index est devant
for (int i = 10; i <= 13; i++) // 4 Broches pour les boutons de réglage
{
pinMode(i, INPUT_PULLUP);
}
// Lecture des positions sauvegardées en EEPROM
unsigned long flag;
EEPROM.get(EEPROM_MAGIC_ADDR, flag);
if (flag == MAGIC_FLAG)
{
// Les données existent, on peut les lire
EEPROM.get(EEPROM_DATA_ADDR, tableauPositions);
}
// Broche Enable du driver (LOW = activé)
pinMode(EN_PIN,OUTPUT);
// Relais pour les voies de garage Activés en LOW et coupés en HIGH (inverse du relais DCC)
for (int8_t i = 0; i<4; i++)
{
pinMode((i+14), OUTPUT);
digitalWrite(i+14, HIGH);
}
// Relais pour le DCC sur le pont
pinMode(DCC_PIN,OUTPUT);
digitalWrite(DCC_PIN,LOW) ; // Relais coupé en LOW et Activé en HIGH = DCC sur le pont en HIGH
// Homing = recherche du point zéro
Homing();
// Place le pont sur le niveau 0 = voie d'entrée
Niveau = 0; // mémorise le niveau actuel
Deplace(tableauPositions[0]);
// Démarre sur menu principal
activeMenu = mainMenu;
activeMenuLength = mainMenuLength;
currentMenuLevel=MAIN_MENU;
updateMenu();
}
void loop()
{
readEncoder();
if (digitalRead(SW_PIN)==LOW) { // Bouton SW ou bouton Orange utilisé
if (currentMenuIndex == 5) { // Si menu Mémorise affiché -> sauvegarde en EEPROM
Memorise();
} else {
for (int8_t i = 0; i<4; i++) { // coupe les relais des voies de garage
digitalWrite(i+14, HIGH);
}
Niveau = currentMenuIndex; // mémorise le niveau actuel
Deplace(tableauPositions[currentMenuIndex]);
updateMenu();
}
} else { // Boutons de réglages utilisés
if (digitalRead(BoutonHaut)== LOW) {
DeplacementReglages(DistanceDeplacement,- VitesseLente);
} else if (digitalRead(BoutonBas)== LOW) {
DeplacementReglages(DistanceDeplacement,VitesseLente);
}
if (digitalRead(BoutonHaut_R)== LOW) {
DeplacementReglages(DistanceDeplacement,- VitesseRapide);
} else if (digitalRead(BoutonBas_R)== LOW) {
DeplacementReglages(DistanceDeplacement,VitesseRapide);
}
}
if (currentMenuLevel = Menu_Reglage) {; //déplacement manuel par les touches
Moteur.run();
}
}
void Deplace(unsigned long position1)
{ // Déplacement vers position1
digitalWrite(EN_PIN, LOW); // active les drivers
digitalWrite(DCC_PIN, LOW); // coupe le DCC sur le pont pendant le déplacement
Moteur.stop (); // au cas où un déplacement manuel serait encore actif
Reculer(1); // nécessaire pour débloquer le moteur après déplacement manuel vers le haut
Moteur.setMaxSpeed(VMax); // Vitesse max
Moteur.setAcceleration(Acceleration); // distance accélération / décélération
lcd.clear();
lcd.setCursor(0, 0); lcd.print("Deplacement en cours ...");
lcd.setCursor(0, 1); lcd.print("Vers Niveau ");
lcd.print((currentMenuIndex > 0) ? ("-") : (" ")); lcd.print(currentMenuIndex);
lcd.setCursor(0,2); lcd.print(Moteur.currentPosition()); lcd.print(" -> "); lcd.print(position1);
Moteur.runToNewPosition(position1); // combine moveTo(position) et runToPosition()
lcd.setCursor(0, 3); lcd.print("Atteint ");
delay(2000);
digitalWrite(EN_PIN, HIGH); // coupe les drivers
digitalWrite((Niveau + 13), LOW); // Active le relais de la voie de sortie
digitalWrite(DCC_PIN, HIGH); // et met le DCC sur le pont
}
Code : Tout sélectionner
// Fonctions pour les menus
//**************************
void readEncoder() // lecture de la position de l'encodeur rotatif
{
bool currentCLK = digitalRead(pinCLK);
if (currentCLK != lastCLK && currentCLK == LOW) {
if (digitalRead(pinDT) != currentCLK) {
currentMenuIndex--; // vers la droite : descend
} else {
currentMenuIndex++; // vers la gauche : monte
}
if (currentMenuIndex < 0) currentMenuIndex = 0;
if (currentMenuIndex >= activeMenuLength) currentMenuIndex = activeMenuLength - 1;
// scroll des 4 lignes visibles
if (currentMenuIndex < topMenuIndex) topMenuIndex = currentMenuIndex;
if (currentMenuIndex > topMenuIndex + 3) topMenuIndex = currentMenuIndex - 3;
updateMenu();
}
lastCLK = currentCLK;
}
void updateMenu()
{
lcd.clear();
for (int i = 0; i < 4; i++) {
int itemIndex = topMenuIndex + i;
if (itemIndex < activeMenuLength) {
lcd.setCursor(0, i);
lcd.print((itemIndex == currentMenuIndex) ? ">" : " ");
lcd.print(activeMenu[itemIndex]);
}
}
}
// Affichage progressif d’une ligne (lettre par lettre)
void afficherProgressivement(int ligne, String texte)
{
lcd.setCursor(0, ligne); lcd.print(" "); // Nettoie la ligne
for (int i = 0; i < texte.length(); i++) {
lcd.setCursor(i, ligne); lcd.print(texte[i]);
delay(80);
}
}
Code : Tout sélectionner
// Fonctions de déplacement & Mémorisation
//****************************************************
void DeplacementReglages (long Distance,int Vitesse) // Déplacements manuels réalisés avec les touches
{
currentMenuLevel = Menu_Reglage;
digitalWrite(DCC_PIN, LOW); // coupe le DCC sur le pont
digitalWrite(EN_PIN, LOW); // active les drivers
Moteur.setSpeed(Vitesse);
Moteur.move(Distance);
if (digitalRead(IR_PIN) == LOW ) // Sécurité si on cherche à monter trop haut
{
Moteur.stop ();
Reculer(200);
}
}
void Memorise ()
{
lcd.clear();
lcd.setCursor(0, 0); lcd.print("Memorisation");
lcd.setCursor(0, 1); lcd.print("Niveau ");
lcd.print((Niveau > 0) ? ("-") : (" ")); lcd.print(Niveau);
lcd.setCursor(0, 2); lcd.print("Valeur: ");
lcd.print(Moteur.currentPosition());
tableauPositions[Niveau] = Moteur.currentPosition();
EEPROM.put(EEPROM_DATA_ADDR, tableauPositions); // Écriture du tableau des positions
EEPROM.put(EEPROM_MAGIC_ADDR, MAGIC_FLAG); // en EEPROM
delay(2000);
activeMenu = mainMenu;
activeMenuLength = mainMenuLength;
currentMenuLevel=MAIN_MENU;
updateMenu();
}
void Homing() { // Recherche du point zéro
digitalWrite(EN_PIN, LOW);
lcd.setCursor(0,0); lcd.print("Recherche position ");
lcd.setCursor(0,1); lcd.print("de reference ... ");
lcd.setCursor(0,2); lcd.print(" ");
Moteur.setMaxSpeed(HOMING_MAXSPEED);
Moteur.setAcceleration(Acceleration);
Moteur.setSpeed(HOMING_SPEED);
while (digitalRead(IR_PIN) == HIGH) { Moteur.runSpeed(); } // Mouvement continu à vitesse fixe
Moteur.stop(); // Arrêt immédiat après détection
Reculer(200); // Reculer un peu pour dégager le capteur
// Définir la position actuelle comme "0"
Moteur.setCurrentPosition(0);
lcd.clear();
lcd.setCursor(0,1); lcd.print("Reference Atteinte");
delay(1000);
}
void Reculer (int Offset)
{
Moteur.move(Offset); // Définir déplacement relatif
while (Moteur.distanceToGo() != 0)
{
Moteur.run(); // Avancer doucement avec accélération
}
}