Affilare le eliche delle frese con Arduino da principiante

Buongiorno, ho intenzione di affilare le eliche delle frese con un sistema motorizzato a due assi. Uno che fa l'avanzamento longitudinale lungo la fresa e l'altro rotativo. In particolare inserendo i valori di avanzamento (passo) sui due assi l'utensile (mola) dovrebbe scorrere lungo la scanalatura dell'elica per affilarla. Come si vede nel video https://www.youtube.com/watch?v=VNDwdyo1ioI

Con l'aiuto di amici abbiamo realizzato questo sketch:

/*
 * SISTEMA AUTOMATICO AFFILATURA FRESE - CONTROLLO CNC ARDUINO (VERSIONE SEQUENZIALE)
 * 
 * Questo programma automatizza l'affilatura di frese a candela eseguendo una passata 
 * per ogni tagliente della fresa. Dopo ogni passata, il mandrino ruota automaticamente 
 * per posizionare il tagliente successivo.
 * 
 * ===================================================================================
 * GUIDA ALL'USO DEL TASTIERINO (4x4)
 * ===================================================================================
 * [A] - SU: Sposta il cursore verso l'alto nel menu.
 * [B] - GIU: Sposta il cursore verso il basso nel menu.
 * [C] - INVIO/CONFERMA: 
 *       - Nel Menu: Entra in modalità modifica o avvia l'azione selezionata.
 *       - Durante l'inserimento: Salva il valore digitato.
 *       - A fine lavoro: Riavvia il ciclo completo di affilatura.
 * [D] - STOP/ANNULLA:
 *       - Durante la lavorazione: Ferma immediatamente i motori e torna al menu.
 *       - Durante l'inserimento: Annulla l'operazione e torna al menu.
 * [*] - RESET: Cancella il numero che stai scrivendo se hai fatto un errore.
 * [0-9] - NUMERI: Usati per inserire i valori dei parametri.
 * 
 * ===================================================================================
 * PARAMETRI DI LAVORO
 * ===================================================================================
 * 1. PASSO ELICA (mm/giro): La distanza lineare che la fresa percorrerebbe in un giro.
 * 2. LUNGHEZZA (mm): Quanto è lungo il tratto del tagliente da affilare.
 * 3. NUM. TAGLIENTI: Quanti taglienti ha la fresa (es. 2, 3, 4).
 * 4. GRADI DIVIS.: L'angolo esatto tra un tagliente e l'altro (es. 90° per 4 taglienti).
 * 
 * HARDWARE: Arduino, LCD I2C, Keypad 4x4, 2x Driver Stepper.
 */

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <AccelStepper.h>

// ===================================================================================
// CONFIGURAZIONE HARDWARE
// ===================================================================================

const float PASSI_PER_MM_LINEARE = 320.0; 
const float PASSI_PER_GIRO_MANDRINO = 1600.0;

const float VELOCITA_MAX = 1000.0;
const float ACCELERAZIONE = 500.0;

const int PIN_STEP_LINEARE = 2; 
const int PIN_DIR_LINEARE  = 3;
const int PIN_STEP_MANDRINO = 4; 
const int PIN_DIR_MANDRINO  = 5;
const int PIN_ENABLE_MOTORI = 8; 

const byte RIGHE = 4; 
const byte COLONNE = 4; 
char keys[RIGHE][COLONNE] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte pinRighe[RIGHE] = {22, 24, 26, 28}; 
byte pinColonne[COLONNE] = {30, 32, 34, 36}; 

LiquidCrystal_I2C lcd(0x27, 20, 4); 
Keypad tastierino = Keypad(makeKeymap(keys), pinRighe, pinColonne, RIGHE, COLONNE);
AccelStepper motoreLineare(AccelStepper::DRIVER, PIN_STEP_LINEARE, PIN_DIR_LINEARE);
AccelStepper motoreMandrino(AccelStepper::DRIVER, PIN_STEP_MANDRINO, PIN_DIR_MANDRINO);

// ===================================================================================
// STATI E VARIABILI
// ===================================================================================

enum StatoSistema {
  MENU_PRINCIPALE,
  EDIT_VALORE,
  LAVORO_ANDATA,
  LAVORO_RITORNO,
  LAVORO_ROTAZIONE,
  LAVORO_COMPLETATO
};

StatoSistema stato = MENU_PRINCIPALE;
int voceSelezionata = 0;

// Parametri Utente
float passoElica = 50.0;
float lunghezzaAffilatura = 150.0;
int numTaglienti = 4;
float gradiDivisione = 90.0;

// Variabili di controllo ciclo
int taglienteCorrente = 0;
String inputBuffer = "";

void setup() {
  lcd.init();
  lcd.backlight();
  lcd.print("AFFILATRICE FRESE");
  lcd.setCursor(0,1);
  lcd.print("Ver. Sequenziale");
  delay(2000);

  pinMode(PIN_ENABLE_MOTORI, OUTPUT);
  digitalWrite(PIN_ENABLE_MOTORI, LOW);

  motoreLineare.setMaxSpeed(VELOCITA_MAX);
  motoreLineare.setAcceleration(ACCELERAZIONE);
  motoreMandrino.setMaxSpeed(VELOCITA_MAX);
  motoreMandrino.setAcceleration(ACCELERAZIONE);

  mostraMenu();
}

void loop() {
  motoreLineare.run();
  motoreMandrino.run();

  char tasto = tastierino.getKey();

  switch (stato) {
    case MENU_PRINCIPALE:
      gestisciNavigazione(tasto);
      break;

    case EDIT_VALORE:
      gestisciInserimento(tasto);
      break;

    case LAVORO_ANDATA:
      if (tasto == 'D') fermaTutto();
      if (motoreLineare.distanceToGo() == 0 && motoreMandrino.distanceToGo() == 0) {
        delay(500);
        lcd.setCursor(0, 3);
        lcd.print("Stato: RITORNO   ");
        motoreLineare.moveTo(0);
        motoreMandrino.moveTo(0);
        stato = LAVORO_RITORNO;
      }
      break;

    case LAVORO_RITORNO:
      if (tasto == 'D') fermaTutto();
      if (motoreLineare.distanceToGo() == 0 && motoreMandrino.distanceToGo() == 0) {
        taglienteCorrente++;
        if (taglienteCorrente < numTaglienti) {
          delay(500);
          lcd.setCursor(0, 3);
          lcd.print("Stato: PROSSIMO  ");
          
          // Ruota il mandrino per il prossimo tagliente
          long passiRotazione = (gradiDivisione / 360.0) * PASSI_PER_GIRO_MANDRINO;
          motoreMandrino.move(passiRotazione);
          stato = LAVORO_ROTAZIONE;
        } else {
          stato = LAVORO_COMPLETATO;
          mostraFineLavoro();
        }
      }
      break;

    case LAVORO_ROTAZIONE:
      if (tasto == 'D') fermaTutto();
      if (motoreMandrino.distanceToGo() == 0) {
        delay(500);
        // Reset coordinate relative per la nuova passata
        motoreLineare.setCurrentPosition(0);
        motoreMandrino.setCurrentPosition(0);
        avviaPassataSincronizzata();
        aggiornaDisplayLavoro();
        stato = LAVORO_ANDATA;
      }
      break;

    case LAVORO_COMPLETATO:
      if (tasto == 'C') { // Ripeti ciclo
        avviaCicloCompleto();
      } else if (tasto == 'D') {
        stato = MENU_PRINCIPALE;
        mostraMenu();
      }
      break;
  }
}

// ===================================================================================
// INTERFACCIA E MENU
// ===================================================================================

void mostraMenu() {
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("--- IMPOSTAZIONI ---");
  
  lcd.setCursor(0,1);
  lcd.print(voceSelezionata == 0 ? ">Elica: " : " Elica: ");
  lcd.print(passoElica, 1);
  
  lcd.setCursor(0,2);
  lcd.print(voceSelezionata == 1 ? ">Lung.: " : " Lung.: ");
  lcd.print(lunghezzaAffilatura, 1);

  lcd.setCursor(0,3);
  if (voceSelezionata == 2) lcd.print(">Taglienti: " + String(numTaglienti));
  else if (voceSelezionata == 3) lcd.print(">Gradi: " + String(gradiDivisione, 1));
  else if (voceSelezionata == 4) lcd.print("> [AVVIA AFFILATURA]");
}

void gestisciNavigazione(char tasto) {
  if (!tasto) return;
  if (tasto == 'A') { voceSelezionata = (voceSelezionata > 0) ? voceSelezionata - 1 : 4; mostraMenu(); }
  else if (tasto == 'B') { voceSelezionata = (voceSelezionata < 4) ? voceSelezionata + 1 : 0; mostraMenu(); }
  else if (tasto == 'C') {
    if (voceSelezionata == 4) avviaCicloCompleto();
    else { stato = EDIT_VALORE; inputBuffer = ""; lcd.setCursor(0,3); lcd.print("Valore:         "); lcd.setCursor(8,3); }
  }
}

void gestisciInserimento(char tasto) {
  if (!tasto) return;
  if (tasto >= '0' && tasto <= '9') { inputBuffer += tasto; lcd.print(tasto); }
  else if (tasto == '*') { inputBuffer = ""; lcd.setCursor(8,3); lcd.print("        "); lcd.setCursor(8,3); }
  else if (tasto == 'C') {
    if (inputBuffer.length() > 0) {
      float val = inputBuffer.toFloat();
      if (voceSelezionata == 0) passoElica = val;
      if (voceSelezionata == 1) lunghezzaAffilatura = val;
      if (voceSelezionata == 2) numTaglienti = (int)val;
      if (voceSelezionata == 3) gradiDivisione = val;
    }
    stato = MENU_PRINCIPALE; mostraMenu();
  } else if (tasto == 'D') { stato = MENU_PRINCIPALE; mostraMenu(); }
}

// ===================================================================================
// LOGICA DI LAVORAZIONE
// ===================================================================================

void avviaCicloCompleto() {
  taglienteCorrente = 0;
  lcd.clear();
  lcd.print("AVVIO AFFILATURA...");
  delay(1000);
  
  motoreLineare.setCurrentPosition(0);
  motoreMandrino.setCurrentPosition(0);
  
  avviaPassataSincronizzata();
  aggiornaDisplayLavoro();
  stato = LAVORO_ANDATA;
}

void avviaPassataSincronizzata() {
  long targetLineare = lunghezzaAffilatura * PASSI_PER_MM_LINEARE;
  float gradiRotazione = (lunghezzaAffilatura / passoElica) * 360.0;
  long targetMandrino = (gradiRotazione / 360.0) * PASSI_PER_GIRO_MANDRINO;

  motoreLineare.moveTo(targetLineare);
  motoreMandrino.moveTo(targetMandrino);

  // Calcolo velocità sincronizzata
  float velBase = 400.0; 
  float tempo = abs(targetLineare) / velBase;
  float velMandrino = abs(targetMandrino) / tempo;

  motoreLineare.setMaxSpeed(velBase);
  motoreMandrino.setMaxSpeed(velMandrino);
}

void aggiornaDisplayLavoro() {
  lcd.clear();
  lcd.print("AFFILATURA IN CORSO");
  lcd.setCursor(0,1);
  lcd.print("Tagliente: ");
  lcd.print(taglienteCorrente + 1);
  lcd.print("/");
  lcd.print(numTaglienti);
  lcd.setCursor(0,2);
  lcd.print("D: STOP");
  lcd.setCursor(0,3);
  lcd.print("Stato: ANDATA    ");
}

void mostraFineLavoro() {
  lcd.clear();
  lcd.print("LAVORO FINITO!");
  lcd.setCursor(0,1);
  lcd.print("Taglienti fatti: ");
  lcd.print(numTaglienti);
  lcd.setCursor(0,2);
  lcd.print("C: RIPETI CICLO");
  lcd.setCursor(0,3);
  lcd.print("D: ESCI AL MENU");
}

void fermaTutto() {
  motoreLineare.stop();
  motoreMandrino.stop();
  stato = MENU_PRINCIPALE;
  mostraMenu();
}

Dovendo utilizzare il tastierino alfanumerico cosa mi consigliate di utilizzare per collegarlo ai piedini 22, 24, 26, 28 e 30, 32, 34, 36.
Ringrazio anticipatamente per l'aiuto che vorrete darmi.
Saluti a tutti, Franco

Ti segnalo che, nella sezione in lingua Inglese, si può scrivere solo in Inglese ... quindi, per favore, la prossima volta presta più attenzione in quale sezione metti i tuoi post; questa volta esso è stato spostato, da un moderatore della sezione di lingua Inglese, nella sezione di lingua Italiana.

Grazie.

Ok scusa.

Ok, ma la domanda quindi qual è esattamente?

Se intendevi solo condividere il codice del progetto, in questo caso per renderlo utile e comprensibile dovresti anche postare lo schema dei collegamenti e la lista dei materiali da utilizzare (e magari foto e/o un video del tutto)...

Credo sia questa:

@ofranco ... intendi cosa usare fisicamente per il collegamento e come effettuare il collegamento o cosa?

Guglielmo

Hehe, ma l'ha aggiunta dopo la mia risposta, non vale! :smiling_face_with_sunglasses:

La scheda di Arduino non ha i pin indicati dal software (22, 24, 26, 28 e 30, 32, 33, 34, 36) e non so come fare a collegare il tastierino visto che i pin sulla scheda Arduino vengono già impegnati dal display e dai due driver dei motori passo passo.
Grazie per la risposta

Ciao Guglielmo, intendo cosa usare fisicamente per il collegamento.

Iniziamo dalle basi: tu parli di "Arduino", ma QUALE Arduino esattamente state usando? Ed il codice che hai postato è il vostro (ma non credo, visto che hai scritto di usare da poco Arduino..) o state usando un codice trovato in rete? Quale?
Perché dal numero di pin sembra si stia parlando di un Mega, e se dici che i pin della scheda sono già tutti impegnati mi "suona" tutto molto strano. Chiarisci meglio di cosa si sta parlando, sia come board Arduino sia come collegamenti attuali.

Sto parlando di Arduino UNO. Il codice è stato realizzato su un forum con l'aiuto di un amico che ha poca disponibilità di tempo.

La UNO, come vedi, non ha tantissimi pin, quindi bisogna per prima cosa verificare QUANTI e quali pin usi per i device che hai elencato, per capire quanti pin ti restano per gestire il tastierino. A quel punto possiamo provare a darti qualche consiglio.
Ma resta il fatto che quel progetto, per come appare nel codice che hai postato, dovrebbe essere per un Mega, non per UNO.

Se tu hai poca esperienza ed il tuo amico invece ce l'ha (il codice non è fatto da un principiante) ma ha poco tempo per seguirti, beh, o hai puntato ad un risultato non alla tua portata (in gergo si chiama "sindrome di Gundam"), o devi "svegliare" un poco l'amico "esperto" ma diciamo eccessivamente "pigro" perché quantomeno ti deve spiegare COME usare quel codice, soprattutto su QUALE board!

PS: sempre che il tuo amico esperto non sia una AI...

Ho idea che chi ha scritto quel software avesse in mente NON Arduino UNO, ma Arduino MEGA ....

Guglielmo

@ Guglielmo. Credo che tu abbia ragione. Qui vedo che ci cono i pin fisici per fare tutti i collegamenti.
@docdoc ho cercato di svegliarlo ma mi ha rinviato a vedere video di youTube per raccapezzarmi perché lui non ha tempo neanche per se stesso.
Mi ha riferito che il software lo ha fatto fare all'AI.
Tuttavia, provengo da un settore elettronico nonché da una lunga esperienza fatta su linux, ho compilato parecchie applicazioni usando il codice, quindi credo di apprendere velocemente le funzionalità di Arduino.
Vi ringrazio ancora per il tempo che mi state dedicando, spero di riuscire a concludere presto questo progetto ambizioso.

P.S. Dimenticavo di dire che ho già realizzato un divisore meccanico utilizzando la tecnologia di Arduino.

Allora il tuo amico, mi spiace dirlo, ma non è affidabile. Far fare codice all'AI ovviamente si può fare, ma devi capire che ci sono alcuni aspetti da considerare:

  1. dato che l'AI prende abbastanza spesso cantonate, è essenziale che quando si prende il codice lo si analizzi per bene per verificare che non abbia fatto idiozie; e questo lo può fare un utente un minimo esperto, e questo implica il secondo punto:
  2. usare l'AI senza avere sufficiente esperienza per valutare il codice generato e verificare se corrisponda alle richieste (ossia se fa correttamente tutto quello che gli si chiede, e magari anche "come" lo fa) è una cosa generalmente deleteria perché a mio avviso rende "pigro" il cervello, soprattutto se si pensa poi di gestire il codice (modificandolo o adeguandolo successivamente a cambiate esigenze)
  3. a meno che uno non accetti di avere "a scatola chiusa" un codice, caricarlo e basta, è comunque necessario studiare (genericamente la programmazione Arduino, e specificatamente il codice) perché in caso di difficoltà, non capendo nulla o quasi del codice e di come funzioni, si genera frustrazione e/o si deve chiedere nel forum (come in questo caso)

In sostanza, quando si parla di codice generato dall'AI, del quale non si comprende il funzionamento e non si sa adeguarlo alle proprie esigenze, già è una cosa non molto positiva (e generalmente non ben vista) per i motivi suddetti. Se poi questo codice lo ha fatto un "amico" usando l'AI ma questo non ha tempo o voglia di stare a seguirti e spiegarti, beh, mi sa che c'è ben poco da fare.
Tra l'altro scusami se te lo dico, ma c'è qualche incongruenza: dici di aver "conosciuto da poco Arduino" ma di aver realizzato (come, sempre con l'AI e l'"amico fantasma"?) un divisore meccanico (che non so cosa sia), e non sai che i pin 22, 24, eccetera NON ci sono su una UNO ma solo una Mega?...

Detto questo, visto che il codice sembra fatto per un Mega, allora o acquisti un Mega e usi quello facendo le connessioni previste dal progetto "del tuo amico", oppure per adeguare il tuo progetto ad una UNO si richiede un minimo di sforzo da parte tua anche perché continuiamo a non avere alcuna informazione relativa ai componenti e soprattutto lo schema delle connessioni (ed alimentazioni, che non vanno trascurate, in particolare da parte di chi non "mastica" un minimo circuiti) .

Una Uno o Nano dovrebbe essere più che sufficiente, riassegnando i pin.
I pinMode e il pilotaggio dei motori sono gestiti dalle librerie?... Quando vengono usate le librerie, non conoscendole è impossibile capire se il programma è corretto!
Uno schema elettrico sarebbe molto utile per capire bene come è stato pensato il circuito.

Ho realizzato lo schema a blocchi del progetto. Spero sia comprensibile.

Le funzioni si possono sintetizzare nel modo seguente:
1)Sistema motore mandrino, compito posizionare manualmente primo tagliente, poi sapendo gradi tra taglienti, i restanti posizionamenti sono fatti dal motore mandrino.
2) Secondo motore provvede all'avanzamento longitudinale, sincronizzato, tra mandrino e fresa.
3)Sistemi input output, tastierino numerico per inserire passo elica, e gradi tra taglienti. Display lcd visualizza numeri inseriti, e sistema menu.

A mio avviso le librerie da utilizzare sono le seguenti:
AccelStepper
Keypad-3.1.1
LiquidCrystal_I2C-1.1.2

Saluti, Franco

Riportare quel codice che giri sulla uno non è nemmeno difficile

Alla fine sono 6 PIN per display e motori e 8 PIN per tastiera

Per assurdo la parte più stupida occupa più PIN di tutto il resto

Ma fa comunque 14, che ci stanno su una uno

Però la vedo dura per il futuro

Ho chiesto a un amico….

che ha chiesto a una AI…

che si è dimenticata la cosa più importante

Di questo passo ora che si accendono i motori vedremo scintille…

Scusa puoi essere più esplicito?

Quale delle mie affermazioni non ti è chiara?

Non ho capito cosa non va nel codice