«

»

Mag 30

Stampa Articolo

Dolly Project con arduino – seconda parte

Riprendendo l’articolo sulla prima parte del progetto Dolly in questo tutorial vedrai come realizzare la parte elettronica del tuo Dolly utilizzando un motore passo-passo bipolare e la shield Motor Shield fe. Dolly project con arduino Inizia configurando la motor shield come nella figura seguente: pin Motor shield fei jumper li puoi impostare come preferisci tra le scelte che la shield ti mette a disposizione, io ho configurato i pin come in figura:

  • PWMA sul pin 3
  • DIRA sul pin 2
  • PWMB sul pin 9
  • DIRB sul pin 8

Ho anche aggiunto un led bianco ad alta luminosità collegato al pin 13, il suo scopo è simulare lo scatto, nel tuo progetto puoi sostituirlo con un fotoaccoppiatore tipo il TLP521-1, in modo da isolare elettricamente lo scatto dal circuito di movimento del dolly. Per collegare l’LCD puoi seguire i miei articoli su questo argomento; ecco una foto del collegamento del display Lcd alla motor shield in modo che i pin utilizzati dalla scheda non siano in conflitto con i pin che utilizzerai per la comunicazione con l’Lcd: connessione lcd motor shield fecome puoi vedere i pin 4 e 6 del display sono collegati rispettivamente ai pin 12 e 11 di arduino, mentre i pin 11,12,13 e 14 del display puoi collegarli ai pin 7,6,5 e 4. I pulsanti che utilizzerai per programmare il dolly ed eseguire tutte le configurazioni sono i seguenti e sono collegati rispettivamente ai pin A0,A1 e A2 rispettivamente:

  • A0 al pulsante
  • A1 al pulsante +
  • A2 al pulsante conf

Riprendo lo sketch presentato nel precedente articolo:

#include <LiquidCrystal.h>

// Input Digitali
int prev = A0;
int next = A1;
int conf = A2;

// Stepper
int motorPinDirA = 2;
int motorPinDirB = 8;
int motorPinPwmA = 3;
int motorPinPwmB = 9;
int nFase=1;

// Led
int pinLed = 13;

// Menu Level
char* menu_principale[4]  =  {"Settaggio","Controllo","Reset Carrello","Avvio"};
char* submenu[3]          =  {"Numero passi x scatto","Intervallo tra i passi","Numero scatti"};

// Init level
int ngiri=0;
float interv=0;
int scatti=0;

int posizione=0;

LiquidCrystal lcd(12, 11, 7, 6, 5, 4);

void setup() {
  lcd.begin(40, 1);
  lcd.print("Dolli Project - mauroalfieri.it");
  delay( 1000 );
  lcd.clear();
  lcd.print( menu_principale[posizione] );

  digitalWrite( pinLed, LOW );

  pinMode(motorPinDirA, OUTPUT);
  pinMode(motorPinDirB, OUTPUT);
  pinMode(motorPinPwmA, OUTPUT);
  pinMode(motorPinPwmB, OUTPUT);
}

void loop() {
  lcd.setCursor(0, 1);
  int pnext = analogRead( next );
  int pprev = analogRead( prev );
  int pconf = analogRead( conf );

  if ( pnext > 1000 || pprev > 1000 || pconf > 1000)
  {
    if ( pnext > 1000 ) { posizione++; lcd.clear(); }
    if ( pprev > 1000 ) { posizione--; lcd.clear(); }

    if ( posizione > 3 ) posizione = 0;
    if ( posizione < 0 )  posizione = 3;

    lcd.print( menu_principale[posizione] );
    //lcd.print(millis()/1000);
    delay(200);

    if ( pconf > 1000 ) {
      lcd.clear();
      switch ( posizione )
      {
        case 0:
          ngiri=0;
          interv=0;
          scatti=0;
          Setting();
          lcd.clear();
          lcd.print( menu_principale[0] );
        break;

        case 1:
          View();
          lcd.clear();
          lcd.print( menu_principale[1] );
        break;

        case 2:
          ResetCarrello();
          lcd.clear();
          lcd.print( menu_principale[2] );
        break;

        case 3:
          Go();
          lcd.clear();
          lcd.print( menu_principale[3] );
        break;
      }
    }
  }
}

void Setting()
{
  int i = 0;
  boolean message = true;

  while ( i < 3 )
  {
    int pnext = analogRead( next );
    int pprev = analogRead( prev );
    int pconf = analogRead( conf );

    if ( message )
    {
      lcd.print( submenu[i] );
      lcd.setCursor(strlen( submenu[i] ), 1);
      lcd.print( ": " );
      lcd.setCursor(strlen( submenu[i] )+2, 1);
      message = false;
    }

    if ( pnext > 1000 || pprev > 1000 || pconf > 1000)
    {
      if ( pnext > 1000 )
      {
        if ( i == 0 ) { ngiri++; lcd.setCursor(strlen( submenu[i] )+2, 1); lcd.print( ngiri ); }
        if ( i == 1 ) { interv += 0.5; lcd.setCursor(strlen( submenu[i] )+2, 1); lcd.print( interv ); lcd.setCursor(strlen( submenu[i] )+8, 1); lcd.print( "sec" ); }
        if ( i == 2 ) { scatti++; lcd.setCursor(strlen( submenu[i] )+2, 1); lcd.print( scatti ); }
      }
      if ( pprev > 1000 )
      {
        if ( i == 0 ) { ngiri--; lcd.setCursor(strlen( submenu[i] )+2, 1); lcd.print( ngiri ); }
        if ( i == 1 ) { interv -= 0.5; lcd.setCursor(strlen( submenu[i] )+2, 1); lcd.print( interv ); lcd.setCursor(strlen( submenu[i] )+8, 1); lcd.print( "sec" ); }
        if ( i == 2 ) { scatti--; lcd.setCursor(strlen( submenu[i] )+2, 1); lcd.print( scatti ); }
      }
      if ( pconf > 1000 )
      {
        lcd.clear();
        i++;
        message = true;
      }
    }
   delay( 200 );
  }
}

void View()
{
  for (int i=0; i<3; i++)
  {
    lcd.clear();
    lcd.print( submenu[i] );
    lcd.setCursor(strlen( submenu[i] ), 1);
    lcd.print( ": " );
    lcd.setCursor(strlen( submenu[i] )+2, 1);

    if ( i == 0 ) { lcd.print( ngiri ); }
    if ( i == 1 ) { lcd.print( interv ); lcd.setCursor(strlen( submenu[i] )+8, 1); lcd.print( "sec" ); }
    if ( i == 2 ) { lcd.print( scatti ); }

    delay( 1000 );
  }
}

void ResetCarrello()
{
  lcd.clear();
  lcd.print( "+ e - sposta carrello, conf esce" );
  int i = 0;

  while ( i < 1 )
  {
    int pnext = analogRead( next );
    int pprev = analogRead( prev );
    int pconf = analogRead( conf );

    if ( pnext > 1000 )
    {
      nFase++;
      if ( nFase > 4 ) nFase = 1;
      gira( nFase );
    }
    if ( pprev > 1000 )
    {
      nFase--;
      if ( nFase < 1 ) nFase = 4;
      gira( nFase );
    }
    if ( pconf > 1000 )
    {
      lcd.clear();
      i++;
    }
    delay ( 200 );
  }
}

void Go()
{
  lcd.print( "Avvio del dolly" );
  for ( int sc=1; sc <= scatti; sc++ )
  {
    for ( int ng=1; ng <= ngiri; ng++ )
    {
      lcd.clear();
      lcd.print( "passo: ");
      lcd.setCursor(7, 1);
      lcd.print( ng );    

      gira( nFase );
      nFase++;
      if ( nFase > 4 ) nFase = 1;

      delay( interv * 1000 );
    }
    lcd.clear();
    lcd.print( "scatto: " );
    lcd.setCursor(8, 1);
    lcd.print( sc );    

    digitalWrite( pinLed, HIGH );
    delay( 1000 );
    digitalWrite( pinLed, LOW );

  }

}

void gira( int nFase ) {

  switch( nFase )
  {

  case 1:
    digitalWrite(motorPinDirA, HIGH);
    digitalWrite(motorPinDirB, LOW);
    digitalWrite(motorPinPwmA, HIGH);
    digitalWrite(motorPinPwmB, LOW);
  break;

  case 2:
    digitalWrite(motorPinDirA, LOW);
    digitalWrite(motorPinDirB, HIGH);
    digitalWrite(motorPinPwmA, LOW);
    digitalWrite(motorPinPwmB, HIGH);
  break;

  case 3:
    digitalWrite(motorPinDirA, LOW);
    digitalWrite(motorPinDirB, LOW);
    digitalWrite(motorPinPwmA, HIGH);
    digitalWrite(motorPinPwmB, LOW);
  break;

  case 4:
    digitalWrite(motorPinDirA, LOW);
    digitalWrite(motorPinDirB, LOW);
    digitalWrite(motorPinPwmA, LOW);
    digitalWrite(motorPinPwmB, HIGH);
  break;

  }
}

rispetto a quello che hai già visto ci sono alcune modifiche in questo sketch utili a far funzionare non solo la parte di trazione del Dolly ma anche la parte di gestione del progetto. la prima modifica riguarda le linee  8-12: in cui definisci i pin come settati sulla motor shield; linea 13: definisci una variabile nFase in cui memorizzerai la fase in cui il motore si trova. linea 16: definisci il pin per lo scatto, in questo esempio il pin 13; linea 19: ho aggiunto una voce al menu principale “Reset Carrello” questo menu ti servirà per riportare la testa del dolly in posizione di partenza dopo avelo utilizzato o per posizionare la testa mobile in una posizione di partenza specifica; linea 29: la modifica a questa linea riguarda i pin di dati a cui è collegato il display Lcd, vedi immagini sopra; linee 40-43: aggiungi le linee che inizializzano i pin dedicati al controllo del motore, con il comando pinMode imposti tutti i pin in modalità OUTPUT; linee 57-58: modifica i limiti alto e basso del menu principale da 2 a 3 dopo aver aggiunto la nuova voce di menu; linee 83-87: aggiungi un case allo switch in modo che al raggiungimento del valore 2 di i sia richiamata la funzione ResetCarrello(); linee 89-93: sono le precedenti linee 83-87 traslate dopo l’aggiunta del precedente menu, attenzione questo case corrisponde al valore 3 di i; Tutto il resto dello sketch resta uguale a parte le due funzioni ResetCarrello() e Go() che vedrai nel dettaglio di seguito: linea 162: definisci la funzione ResetCarrello(); linee 164-165: ripulisci il display e scrivi a video le istruzioni per eseguire il reset, come puoi leggere a video le istruzioni indicano di utilizzare i pulsanti + e – per spostare il motore avanti e indietro e il pulsante conferma per uscire da questo menu e poter procedere all’avvio del programma del Dolly; linea 166: definisci una variabile di tipo integer il cui valore sarà controllato da un ciclo while e incrementato alla pressione del pulsante conf per uscire dal ciclo e dalla funzione ResetCarrello() fino a quel momento la funzione sposterà il carrello in avanti e indietro fino al punto di partenza da te definito; linea 170-172: sono linee già incontrate più volte e servono a leggere il valore dei pulsanti ad ogni ciclo del while; linea 174: verifica la pressione del pulsante + (next); linea 176: incrementa il valore della variabile nFase che indicherà al motore di proseguire con il passo successivo a quello in cui si trova; linea 177: è un controllo sul valore della variabile nFase in modo che non vada oltre il valore 4, essendo 4 le fasi che il motore possiede, se utilizzi un motore con più di 4 fasi dovrai modificare questa condizione in modo da fargli compiere tutte le fasi di cui il motore dispone; linea 178: richiama la funzione gira() passandogli il numero corrispondente alla fase in cui il motore dovrà portarsi, questa funzione  la analizzerò successivamente; linee 180-185: esegui le stesse operazioni delle linee 176-178 ma decrementando il valore di nFase per ottenere la rotazione del motore in senso contrario, ossia alla pressione del pulsante – ( prev ) il motore compirà una serie di passi in senso opposto al precedente; linee 186-190: alla pressione del pulsante conf lo sketch incrementa i portando il suo valore a 1, questo ha come effetto che la condizione while ( i < 1 ) presente alla linea 168 non è più vera e il ciclo while si interrompe uscendo dalla funzione ResetCarrello() e ridando il controllo alla funzione loop(); linea 191: prima della conclusione di ogni ciclo di while attend un tempo di 200 millisecondi necessari sia a registrare il corretto input da parte dei pulsanti sia a far eseguire al motore ciascun passo; il funzionamento del codice che hai appena visto è semplice una volta selezionata la funzione ResetCarrello() tenendo premuto il pulsante + il motore avanza, tenendo premuto il pulsante – il motore indietreggia, la pressione del pulsante conf interrrompe la funzione e ripassa il controllo alla loop(); linee 195-226: definisci la funzione Go(); linea 197: scrivi sul display la frase “Avvio del dolly”; linea 198: inizia un ciclo for in funzione del parametro scatti opportunamente impostato in fase di setting del dispositivo, se hai impostato di eseguire 3 scatti, ad esempio, il ciclo for partirà da 1 ed ad ogni ciclo incrementerà il valore della variabile sc fino al raggiungimento del numero di scatti impostati; linea 200: imposta un ciclo for sulla variabile ngiri in cui hai memorizzato il numero di passi che il motore deve compiere tra uno scatto ed il successivo; linee 202-205: per ciascun passo scrivi sul display il numero di passo a ci sei arrivato; linea 207: chiama la funzione gira() passandogli il valore della variabile nFase ossia il numero di fase a cui il motore deve portarsi, ricorda che le fsi di un motore bipolare sono solitamente 4 anche se i passi necessari a compiere un giro completo possono essere molti di +, ad esempio un  motore con passo da 1.8° è un 200 passi ( 360° / 1.8° = 200 ); linea 208, incrementa il valore della variabile nFase per il giro succesivo; linea 209: controlla che il numero di fase non sia superiore a 4, in tal caso reimposta a 1 tale valore; linea 211: è il cuore del sistema di spostamento, avendo definito un tempo che il dolly deve attendere tra un passo ed il successivo l’istruzione delay in questa linea si occupa di far rispettare questa impostazione, per ottenerla utilizzi un’operazione matematica semplice: ( intervallo * 1000 millisecondi ) conoscendo il valore di intervallo puoi ricavare facilmente che se interv vale 0,50 il tempo atteso sarà di 500 millisecondi, se interv vale 1 il tempo sarà di 1 secondo ( 1000 millisecondi ); linee 213-216: scrivi sul display il valore dello scatto a sui sei arrivato; linee 218-220: esegui lo scatto vero e proprio portando l’uscita 13 ad HIGH, attendi 1 secondo e riporta a LOW tale pin; linee 226-260: definisci la funzione gira() il cui scopo è far avanzare il motore attraverso le sue 4 fasi secondo il valore nFase ( numero di fase da eseguire ) che viene di volta in volta passato alla funzione. Nel prossimo articolo ti mostrerò come programmare il Dolly e utilizzarlo. Buona realizzazione.

Permalink link a questo articolo: http://www.mauroalfieri.it/elettronica/dolly-project-con-arduino-seconda-parte.html

9 comments

Vai al modulo dei commenti

  1. davide

    ciao mauro, innanzitutto volevo farti i complimenti per il tuo sito e tutti i programmi che hai sviluppato.
    ho appena finito di assemblare questo ed è fantastico, volevo fargli un paio di modifiche se è possibile.
    vorrei nel void reset carrello cambiare il modo di spostamento, cioè invece di spostarlo con i pulsanti volevo mettere un potenziometro. avevo pensato ad un potenziometro che variasse il delay tra una fase e l’altra del motore in modo da poter variare la velocità e un interruttore per dirgli avanti e indietro. E nel void go volevo inserire il pulsante conf in modo da poter interrompere il programma se ne avessi la necessità.
    ho provato a fare un po di modifiche ma non sono arrivato alle conclusioni che desideravo..spero tu mi possa essere d’aiuto.

    grazie ciao!

    1. Mauro Alfieri

      Ciao Davide,
      ottimo !!! Mi fa piacere non solo che tu abbia realizzato il kit Dolly ma che stia tentando di farlo evolvere.

      Per il potenziometro puoi leggere un ingresso analogico libero e usare quel valore per regolare il delay tra le fasi, dovendo comunque mantenere i due pulsanti per regolare avanti e indietro ti suggerisco di non cambiare la funzione di reset non vedo c’è vantaggi otterresti.

      Per la funzione di stop nella fase di go, sul blog ho pubblicato una evoluzione del progetto che aggiunge anche questa funzione, se non ricordo male.

      In questi giorni sto pubblicando una nuova serie di articoli dedicati al Dolly Photo, con tante nuove chicche 🙂

      Mauro

      1. davide

        immagino bisogni modificare la riga 211. io ho provato a modificarla così, ma credo che ho proprio sbaliato strada..se mi daresti una dritta mi farebbe molto piacere 🙂

        void Go()
        { int velocita = analogRead(ritardo);
        int delayTime=map(velocita,0,1024,0,500);

        lcd.print( “Avvio del dolly” );
        for ( int sc=1; sc <= scatti; sc++ )
        {
        for ( int ng=1; ng 4 ) nFase = 1;

        delay(delayTime );
        }
        lcd.clear();
        lcd.print( “scatto: ” );
        lcd.setCursor(8, 1);
        lcd.print( sc );

        digitalWrite( pinLed, HIGH );
        delay( 1000 );
        digitalWrite( pinLed, LOW );

        }

        }

        comunque volevo modificare il reset con un potenziometro cosi da poter fare il reset con il potenziometro aumentando la velocità del carrello e se ne avessi la necessità anche poter usare il dolly come slitta per le riprese. cioè volevo praticamente farla andare senza fermarsi e decidere manualmente la velocità.
        grazie
        davide

      2. davide

        scusami sono riuscito a farlo andare 🙂 grazie

        1. Mauro Alfieri

          Ciao Davide,
          bene sono contento .. lo spirito del Blog è stimolare la capacità di ognuno a provare, fare e sperimentare.
          Se vuoi condividere il tuo successo sul Blog sarò lieto di farlo, inviami uno zip con lo sketch, foto, video al progetto alla casella email info.

          Mauro

  2. Vincenzo

    Ciao Mauro, e se al posto della shield utilizzassi un integrato L293D? con quale logica dovrò modificare i pin da te impostati come:

    // Stepper
    int motorPinDirA = 2;
    int motorPinDirB = 8;
    int motorPinPwmA = 3;
    int motorPinPwmB = 9;

    1. Mauro Alfieri

      Ciao Vincenzo,
      la cosa migliore è collegare gli input del L293D ai medesimi pin della shield utilizzata in questo progetto.
      Se non ricordo male la motor shield che ho usato è basata sul tuo stesso integrato per cui puoi usare lo schema della shield ed applicarlo al tuo caso.

  3. Andrea

    Salve, sto realizzando una dolly ma sfortunatamente ho recuperato una ADFRUIT shield scartata da un vecchio progetto .

    il mio problema è che la shield utilizza alcuni pin del monitor LCD ….puo consigliarmi qualche cosa in merito ?? putroppo non ci sono molti schemi o tutorial su questa shield .

    Grazie

    Andrea.

    1. Mauro Alfieri

      Ciao Andrea,
      se due shield usano i medesimi pin non puoi far altro che modificarli nello sketch e modificare il circuito in modo che quei pin siano connessi altrove su arduino, in alternativa sto lavorando ad una scheda dolly dedicata che sarà distribuita dal sito http://www.lemontech.cc ma non so ancora tra quanto sarà disponibile.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Puoi usare i seguenti tag ed attributi HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>