Coulisse a 6 binari in scala TT controllata con Arduino.
La parte meccanica.
Questa coulisse è stata realizzata con un motore stepper ricavato da un vecchio scanner posizionato centralmente, mentre alle estremità sono stati usati 2 linear bearing.
La soluzione è abbastanza affidabile ma penso sia l’ideale per ponti trasbordatori di limitate dimensioni, mentre per coulisse piuttosto lunghe sarebbe meglio usare 2 motori stepper alle estremità (magari in futuro …)
La coulisse misura 150 cm x 21 cm e permette il posizionamento di 6 binari in scala TT
Le barre e il motori sono stati fissati alla struttura con barre filettate per permettere la regolazione della altezza e della planarità della coulisse.
La parte di controllo.
Il controllo della coulisse è demandato ad Arduino Uno e a componenti reperibili facilmente su internet (e-bay):
- Alimentatore 5V – 12V per alimentare Arduino e il motore passo-passo
- Sensori ottici per i 2 finecorsa
- Encoder rotativo per selezionare i 6 binari
- Display 4 digit per indicare il binario selezionato e il movimento delle coulisse
- Scheda stepper driver
- Screw shield per semplificare i collegamenti tra i componenti
I collegamenti.
Questo è lo schema di collegamento.
Il programma.
// Controllo di un motore stepper per movimento coulisse con 6 binari. // Comandi di posizione con encoder rotativo e display 4 digit 7 segmenti // Questo sketch: // - muove un motore stepper // - scrive e legge posizione nella eeprom // - D2 e D3 controllano finecorsa // La selezione della posizione viene gestita ruotando un encoder rotativo // e utilizzando lo switch per abilitare il movimento // La posizione selezionata viene evidenziata su un modulo 4 digit 7 segmenti // che è gestito dalla libreria sviluppata da avishorp. // https://github.com/avishorp/TM1637 // // Pin usati // A0 : Encoder rotativo (usato come digital) // A1 : Encoder rotativo (usato come digital) // 2 : interrupt - encoder switch // 3 : display CLK // 4 : display DIO // 6 : sensore controlla finecorsa alto // 7 : sensore controlla finecorsa basso // 8 : Stepper Motor Pin1 // 9 : Stepper Motor Pin2 // 10 : Stepper Motor Pin3 // 11 : Stepper Motor Pin4 // Modifiche // Who______ When______ Why________________________________ // Gavi FEB.2015 Scritta // Gavi GEN.2017 Inseriti controlli finecorsa // Gavi FEB.2017 Inserita scrittura posizione nella EEPROM // Gavi MAR.2017 Impostazione posizione con rotary encoder e display 7 segmenti #include <EEPROM.h> #include <AccelStepper.h> #include <TM1637Display.h> // Motor pin definitions #define motorPin1 11 // IN1 on the ULN2003 driver 1 #define motorPin2 9 // IN2 on the ULN2003 driver 1 #define motorPin3 10 // IN3 on the ULN2003 driver 1 #define motorPin4 8 // IN4 on the ULN2003 driver 1 // Initialize with pin sequence IN1-IN3-IN2-IN4 for using the AccelStepper with 28BYJ-48 AccelStepper stepper(AccelStepper::HALF4WIRE, 8, 10, 9, 11); String inputString = ""; // a string to hold incoming data boolean stringComplete = false; // whether the string is complete boolean sendMsg = false; volatile boolean muoviCoulisse = false; char inChar; int pos; int savedPos; int passi_tot = 0; float pos_cdb1 = 0; float pos_cdb2 = pos_cdb1 + 1520; float pos_cdb3 = pos_cdb2 + 1520; float pos_cdb4 = pos_cdb3 + 1520; float pos_cdb5 = pos_cdb4 + 1520; float pos_cdb6 = pos_cdb5 + 1520; const int fineAlto = 6; // definisco pin finecorsa const int fineBasso = 7; // gestione encoder rotativo unsigned long currentTime; unsigned long loopTime; const char enc_A = A0; // pin A0 const char enc_B = A1; // pin A1 //const byte interruptPin = 2; const byte enc_sw = A2; unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev=0; // 4 digit display const int CLK = 3; //Set the CLK pin connection to the display const int DIO = 4; //Set the DIO pin connection to the display TM1637Display display(CLK, DIO); //set up the 4-Digit Display. void setup() { Serial.begin(9600); // reserve 200 bytes for the inputString: inputString.reserve(100); // Controllo motore passo-passo stepper.setMaxSpeed(200); stepper.setAcceleration(100); // savedPos = EEPROM.read(0); if (savedPos == 1) {stepper.setCurrentPosition(pos_cdb1);} if (savedPos == 2) {stepper.setCurrentPosition(pos_cdb2);} if (savedPos == 3) {stepper.setCurrentPosition(pos_cdb3);} if (savedPos == 4) {stepper.setCurrentPosition(pos_cdb4);} if (savedPos == 5) {stepper.setCurrentPosition(pos_cdb5);} if (savedPos == 6) {stepper.setCurrentPosition(pos_cdb6);} pos = savedPos; //pos = 6; pinMode(13, OUTPUT); // Finecorsa pinMode(fineAlto, INPUT); pinMode(fineBasso, INPUT); // encoder pinMode(enc_A, INPUT); pinMode(enc_B, INPUT); pinMode(enc_sw, INPUT_PULLUP); // pinMode(interruptPin, INPUT_PULLUP); // attachInterrupt(0, muovi, CHANGE); // Questo non va per ora uso la forma deprecata //attachInterrupt(digitalPinToInterrupt(interruptPin), muovi, CHANGE); currentTime = millis(); loopTime = currentTime; // display display.setBrightness(0x0a); //set the diplay to maximum brightness } void loop() { if (muoviCoulisse) { muoviCoulisse = false; if (pos == 1) { stepper.enableOutputs(); stepper.moveTo(pos_cdb1); } if (pos == 2) { stepper.enableOutputs(); stepper.moveTo(pos_cdb2); } if (pos == 3) { stepper.enableOutputs(); stepper.moveTo(pos_cdb3); } if (pos == 4) { stepper.enableOutputs(); stepper.moveTo(pos_cdb4); } if (pos == 5) { stepper.enableOutputs(); stepper.moveTo(pos_cdb5); } if (pos == 6) { stepper.enableOutputs(); stepper.moveTo(pos_cdb6); } } // Se la coulisse è in posizione comunico e // disabilito outputs per evitare surriscaldamento del motore if (stepper.distanceToGo() == 0) { stepper.disableOutputs(); // salvo posizione nella eeprom if (EEPROM.read(0) != pos) { EEPROM.write(0,pos); } // display posizione corrente display.showNumberDec(pos); // controllo encoder per nuova posizione currentTime = millis(); if(currentTime >= (loopTime + 5)){ // 5ms since last check of encoder = 200Hz encoder_A = digitalRead(enc_A); // Read encoder pins encoder_B = digitalRead(enc_B); if((!encoder_A) && (encoder_A_prev)){ // A has gone from high to low if(encoder_B) { // B is high so clockwise // incrementa posizione if(pos + 1 <= 6) {pos = pos + 1;} else {pos = 1;} } else { // B is low so counter-clockwise // decrementa la posizione if(pos - 1 >= 1) {pos = pos - 1;} else {pos = 6;} } display.showNumberDec(pos); } encoder_A_prev = encoder_A; // Store value of A for next time loopTime = currentTime; // Updates loopTime } if (digitalRead(enc_sw) == LOW) { muoviCoulisse = true; } } else { // se la coulisse è in movimento // display 88 //controllo di non essere ai finecorsa display.showNumberDec(88); if (digitalRead(fineAlto) == HIGH) { stepper.setCurrentPosition(pos_cdb6); } if (digitalRead(fineBasso) == HIGH) { stepper.setCurrentPosition(pos_cdb1); } } stepper.run(); } void muovi() { muoviCoulisse = true; } |