Coulisse con Arduino

gavinca   Novembre 8, 2017   Commenti disabilitati su Coulisse con Arduino
Print Friendly, PDF & Email

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;
}