martedì 3 ottobre 2017

iBoard DIY - una lavagna controllata via WEB

Ciao a tutti rieccomi quà,
mi ero promesso di non costruire più CNC e invece ci sono cascato di nuovo... non ho resistito!

Questa volta però è un pò diverso perchè l'aspetto più importante del progetto sul quale ho speso più tempo ed energie non è tanto la parte meccanica quanto quella software, non ho voluto utilizzare soluzioni già pronte ma inventarmene uno tutto mio mettendo insieme pezzi di codice opensource.




L'idea è quella di realizzare una lavagna auto cancellabile che potesse scrivere e disegnare in tempo reale attraverso un'interfaccia web e quindi anche da uno smartphone.

A cosa mi serve? non lo so! faccio questo più che altro per studio e ricerca, chissà se gli troverò mai un utilizzo... anche se a pensarci bene però una mezza idea ce l'avrei!
Mi piacerebbe (ma devo avere il consenso della moglie) posizionare la lavagna in un posto tipo in cucina appesa al muro e automatizzare la stampa di messaggi automatici come ad esempio qualche notizia presa via web oppure il meteo di oggi, gli appuntamenti della giornata recuperati da Google Calendar,un disegno fatto a mano, note/appunti scritti quando sono in auto e tanto altro... per adesso ci gioca mio figlio con il Tablet.





Non nascondo che sono stato fortemente ispirato da un progetto esistente (iBoardbot). Il progetto iBoardbot è molto simpatico ma non mi solleticava l'idea di dover attivare una licenza per poter far funzionare il giocattolino così ho pensato di inventarmene una tutta mia e soprattutto un pò più grande.

Per agevolare la lettura di questo articolo ho  organizzato i contenuti in macro-sezioni:

  • Componentistica
  • Logica di funzionamento
  • Meccanica
  • Elettronica
  • Software
  • Considerazioni


Componentistica

Il progetto è basato principalmente sull'utilizzo di un Raspberry Pi3, di seguito elenco i componenti necessari per assemblare questa lavagna.


Componenti meccanici Componenti elettronici
  • Tavole di legno per la struttura
  • Pezzi stampati in ABS
  • Circa 1mt. di cinghia T2
  • 2 pulegge GT2
  • 2 mt. di cinghia GT2
  • 1 supporto in ferro per nema 17
  • 1 stelo acciaio diam. 10mm x 500mm
  • 1 tubo alluminio da 6mm
  • 1 cuscinetto 
  • 1 profilo alluminio a L
  • 1 lastra di vetro bianco
  • Qualche vite piccola da legno
  • Viti, bulloni e rondelle M3 varie misure
  • 2 cuscinetti autolubrificanti in bronzo diam. 10mm

  • Raspberry Pi 3 model B
  • Arduino Uno
  • CNC shield
  • 2 motori Nema 17
  • 1 Servo SG90 9g
  • Riduttore di tensione IN 6-24V OUT doppio USB 5V
  • Cavetti elettrici vari
  • Alimentatore 12Volt
  • 2 Driver pololu A4988

Logica di funzionamento

La scelta di adottare un Raspberry è dettata dal fatto che avendo un sistema operativo linux mi da la libertà di organizzare le cose a mio piacimento senza alcun tipo di vincolo, può andare in rete tramite WiFi e ultima ma non meno importante, posso farlo lavorare come un web server, ed è proprio questa la chiave di tutto perchè configurando opportunamente il router di casa posso accedere dall'esterno al Raspberry con il browser di uno smartphone.

In parole povere il Raspberry è il webserver sul quale gira un sito con l'interfaccia per scrivere e disegnare poi il disegno in formato SVG viene inviato, sempre al Raspberry che lo converte in GCODE e lo processa per azionare i motori.

Più avanti nella sezione software spiegherò in dettaglio i processi.

Meccanica

A differenza di tutte le altre cnc che ho realizzato con materiali di recupero questa l'ho progettata da zero in Rhino con l'obbiettivo di stampare in ABS tutti i componenti necessari e assemblare il tutto senza sorprese o dover ricorrere a soluzioni posticce. Inoltre ho sviluppato anche tutta la parte software in grado di dialogare via web e pilotare la testina per disegnare e all'occorrenza cancellare la lavagna.



In termini di dimensioni ho cercato di far rientrare tutto in una scatola non troppo ingombrate e facilmente installabile perchè alla fine dei giochi da tale scatola vorrei che uscisse un solo cavo, quello della 220 Volt e nient'altro, un pò come fosse un piccolo plotter.


Meccanicamente ho progettato una struttura  leggera con pochi pezzi ma ottimizzati per lo scopo, ho cercato di miniaturizzare il più possibile i componenti soprattutto quelli dedicati alla testina.









Modellare i pezzi è stato facile e se vogliamo anche veloce ma la cosa che mi ha fatto perdere un botto di tempo è stato riuscire a stamparli rispettandone le misure finali, provo a spiegarmi meglio...

Se ad esempio ho il modello 3D di un cubo 20x20x20 con un foro centrale diam. 6 mm quando lo si stampa le misure finali non saranno mai quelle del disegno originale per il fatto che il materiale di stampa (ABS nel mio caso) tende a restringersi durante la fase di raffreddamento. La cosa poco simpatica è che ad esempio i fori si riducono e le parti esterne si restringono. 

Di quando si restringono i pezzi? boh! ho letto che la percentuale di restringimento può cambiare dalla marca del filamento usato e addirittura dal colore.

Io ho risolto la questione stampando prima dei pezzi campione e misurando le dimensioni finali, poi facendo delle proporzioni ho ricavato una percentuale di restringimento.
Questo scherzetto mi ha costretto a modificare tutte le misure dei pezzi in 3D con la conseguente perdita di tempo.

Oltre a questo mi sono ritrovato a dover rimodellare alcuni pezzi perchè una volta stampati non di adattavano bene o semplicemente mi ero dimenticato qualcosa (un foro, un perno, ecc...)
















Mi sono reso conto che progettare un prototipo da zero comporta il dover rifare e rivedere ogni singolo pezzo e riadattarlo perché funzioni come dovrebbe, insomma bisogna essere pronti a rimettere in gioco tutto qualora si dovessero incontrare ostacoli o impedimenti.
Giusto per rendere l'idea la testina l'ho dovuta ristampare 5 volte e ancora non è alla situazione ottimale (ma fa il suo dovere).


Una volta stampati i pezzi il montaggio è molto semplice, basta rimediare delle pareti in multistrati e assemblarle a formare una C.




I pezzi stampati in ABS vengono installati all'interno della struttura a C.











La cosa più importante è fare in modo che lo stelo da 10 mm su cui scorrerà il carrello sia perfettamente perpendicolare alla struttura.



Per permettere lo scorrimento del carrello sullo stelo ho comprato su ebay una bronzina o meglio un cuscinetto lineare auto-lubrificante.
 





La bronzina s'incastra nel supporto in ABS del motore e per tenerla ferma l'ho fermata con 2 viti.

Nei giorni successivi avevo stampato 2 coperchi appositi per fermare le bronzine, che alla fine non ho ho montato, più che altro per pigrizia di smontare di nuovo tutto.

















Assemblaggio del supporto inferiore con micro-switch di finecorsa:




Assemblaggio della testina di stampa:





















La meccanica senza elettronica e software serve a ben poco ed è qui che entra in gioco la coppiata Raspberry + Arduino Uno.

Elettronica

I componenti elettronici in gioco sono principalmente un Raspberry Pi 3, un Arduino Uno e un CNC Shield.

Il Raspberry è il cuore principale perchè gestisce tutte le operazioni e i segnali di input e output, Arduino ha lo scopo di gestire la corrente che passa nei motori e di azionare un servo per muovere la penna e il cancellino, il CNC shield ha a bordo dei driver pololu A4988 che a loro volta azionano dei Nema 17.

Oltre a questi componenti fondamentali troviamo un alimentatore da 12 Volt, un riduttore di tensione, un relè qualche cavo elettrico.
L'alimentazione ha il compito di alimentare il CNC shield e quindi i nema 17 e, attraverso un riduttore di tensione con uscita USB, il Raspberry e il servo motore.

Arduino è alimentato direttamente dal Raspberry tramite un cavetto usb e per semplificare un pò le cose ho installato sul Raspberry l'IDE di Arduino così che posso fare modifiche allo sketch al volo direttamente dall'interfaccia desktop de Raspberry anche da remoto via VNC.

Uno degli obiettivi che mi ero prefissato  era di avere una macchina senza tanti file che uscivano fuori, trasformatori o driver esterni ma con il solo filo della 220 V che uscisse.
Detto questo ho cercato di incastrare tutto all'interno della struttura.

Ho tagliato un rettangolo di compensato dove ho predisposto i fori per avvitarci le 3 schede principali e fermare i fili.


Questo è lo schema dei collegamenti elettrici ultimo:








Infine chiuderò il resto con un coperchio di faesite bianca.

Software

La parte software di questo progetto è la cosa più importante perchè è quella che permette di gestire ogni singolo comportamento della macchina in base alle proprie esigenze.

L'utente che vorrà interagire con la macchina (o lavagna) avrà a disposizione un'app web basata su jQuery che permetterà di disegnare a mano libera o di scrivere un testo e poi inviare il tutto al webserver (Raspberry) che dovrà processare il dato, convertirlo in Gcode e infine trasformarlo in segnali per i motori.
Detta così può sembrare una cosa complicata ma se si isolando tutti i vari processi in piccole operazioni atomiche tutto diventa più semplice e comprensibile.

I linguaggi di programmazione che sarebbe opportuno conoscere sono:

  • Linux bash
  • PHP
  • Python
  • HTML
  • Javascript + jQuery


I pezzi di software in gioco per questo progetto sono i seguenti:

  • PyCNC (gestione motori e gcode)
  • svg2gcode (conversione da svg a gcode)
  • grecode (manipolazione gcode)
  • easysvg (generatore testi in svg)
  • iBoard.class.php (classe principale di controllo)
  • iBoard.js (classe javascript lato client che dialoga con iBoard.class.php)

Come ho accennato nell'introduzione il principio su cui si basa tutto è il formato SVG, molto utilizzato nel web per disegnare soprattutto grafici.

Se provate ad aprire con il blocco note un qualunque file .SVG noterete come prima cosa che è un formato testuale e all'interno è presente una struttura XML che contiene dei tag <path> con all'interno delle coordinate X,Y ed è proprio questo aspetto che permette di ottenere del Gcode.

in linea di massima questo è il flusso dati che ho ipotizzato:



Webserver Apache + PHP

La configurazione del server (Raspberry) è un pò laboriosa ma nulla di così complesso.

Installare Apache2

sudo apt-get update
sudo apt-get install apache2

Installare PHP

 sudo apt-get install php5 libapache2-mod-php5 php5-mcrypt

Dopo aver installato Apache e PHP e necessario configurare Apache in modo da farlo girare con l'utente "pi" e group "pi" perchè quando sarà il momento di eseguire gli script l'utente di apache non sarà in grado di eseguirli. Il file su cui bisognerà intervenire è questo
/etc/apache2/httpd.conf
modifica da effettuare:
User pi
Group pi

Ora occorre creare un virtualhost e facendolo puntare alla directory del progetto.
La cartella dove creare un vhost si trova qui:
/etc/apache2/sites-enabled
è sufficiente creare un file con estensione .conf ad esempio
iboard.tuodominio.com.conf 
all'interno del file basta inserire questa configurazione



Fatte le modifiche è occorre riavviare il servizio apache
sudo /etc/init.d/apache2 stop
sudo /etc/init.d/apache2 start
Per poter vedere se la configurazione è andata a buon fine basta aprire il browser di un PC in rete e digitare il nome di dominio che avete scelto.

Se non è stato configurato il router per accettare l'ingresso delle chiamate http e se non è stato ancora registrato un dominio è sufficiente aggiungerlo nel file hosts del pc.
Su Windows il file si trova qui:
C:\Windows\System32\drivers\etc\hosts

In fondo al file è necessario aggiungere una riga come questa
[IP Raspberry] iboard.tuodominio.com
es.
192.168.1.70  iboard.tuodominio.com

Salvare il file e digitare sul browser del PC http://iboard.tuodominio.com, se è stato fatto tutto bene si dovrebbe vedere la pagina di benvenuto di Apache.

Libreria per controllo motori stepper

Senza un software capace di inviare segnali ai driver dei motori stepper questo progetto non esisterebbe.
Per poter convertire una istruzione gode in movimento è necessaria una libreria capace di interpretare il dato e gestire i segnali in uscita.
La particolarità che dovrà avere questa libreria è che le istruzioni gcode dovranno essere lanciate in bash a linea di comando.

Libreria PyCNC (python)
Prima di mettermi a scrivere qualcosa da zero ho fatto una lunga ricerca ed alla fine ho trovato su GitHub una libreria scritta in Python chiamata PyCNC .

PyCNC è stata sviluppata da un  ragazzo Nikolay Khabarov molto gentile e disponibile perchè ad ogni domanda che gli facevo mi ha sempre risposto con precisione e ottime soluzioni. a questo link è possibile consultare i quesiti tecnici che gli avevo posto e le sue relative risposte.
Spiego in breve il motivo per il quale avevo contattato Nikolay.
La sua libreria riesce a gestire fino a 5 assi con motori stepper mentre nel mio progetto ho anche un piccolo servo utilizzato per azionare la penna ed il cancellino.
Secondo Nikolay la gestione del servo era possibile ma dopo aver fatto diversi test e modificato i sorgenti del suo codice siamo giunti entrambi alla conclusione che per come era stata scritta non era possibile farlo o meglio capitava che mentre gli stepper giravano mi si generavano delle interferenze sul servo.

La soluzione che ho adottato è stata quella di inserire nel progetto un Arduino Uno con il compito di azionare penna, cancellino ed un relè per la gestione del risparmio di energia che spiegherò più avanti.
Per far dialogare la libreria PyCNC con Arduino ho dovuto fare diverse modifiche al codice di Nikolay.
PyCNC detto in parole povere non fa altro che parsare ogni singola riga di gcode e identificare i comandi (es.  G1,G2,G3,M3,M5, ecc....) e chiamate delle funzioni specifiche che generano segnali di uscita per i motori.

Tutti i parametri dei motori e la configurazione dei pin si trova in questo file:
PyCNC/cnc/config.py
ecco alcune linee di codice di configurazione:
MAX_VELOCITY_MM_PER_MIN_X = 10000
MAX_VELOCITY_MM_PER_MIN_Y = 10000
MAX_VELOCITY_MM_PER_MIN_Z = 600
MAX_VELOCITY_MM_PER_MIN_E = 1500
MIN_VELOCITY_MM_PER_MIN = 1
# Average velocity for endstop calibration procedure
CALIBRATION_VELOCITY_MM_PER_MIN = 1000
# Stepper motors steps per millimeter for each axis.
STEPPER_PULSES_PER_MM_X = 80.5
STEPPER_PULSES_PER_MM_Y = 39.75
STEPPER_PULSES_PER_MM_Z = 400
STEPPER_PULSES_PER_MM_E = 150
# -----------------------------------------------------------------------------
# Pins configuration.
# Enable pin for all steppers, low level is enabled.
STEPPERS_ENABLE_PIN = 26
STEPPER_STEP_PIN_X = 21
STEPPER_STEP_PIN_Y = 16
STEPPER_STEP_PIN_Z = 12
STEPPER_STEP_PIN_E = 8
STEPPER_DIR_PIN_X = 20
STEPPER_DIR_PIN_Y = 19
STEPPER_DIR_PIN_Z = 13
STEPPER_DIR_PIN_E = 7
# Mirco
PEN_PIN = 9
ERASER_PIN = 11
DRIVERS_PIN = 5
# Mirco
SPINDLE_PWM_PIN = 4
FAN_PIN = 27
EXTRUDER_HEATER_PIN = 24
BED_HEATER_PIN = 22
EXTRUDER_TEMPERATURE_SENSOR_CHANNEL = 2
BED_TEMPERATURE_SENSOR_CHANNEL = 1
ENDSTOP_PIN_X = 23
ENDSTOP_PIN_Y = 10
ENDSTOP_PIN_Z = 25



Quello che ho fatto è inventarmi 5 nuovi comandi Gcode M333, M444, M555, M666, M777 e implementarli in PyCNC dove ognuno di essi genera segnali di uscita sui pin del Raspberry.
In particolare 
  • M333 aziona il relè per alimentare i driver
  • M444 disattiva il relè per alimentare i driver
  • M555 servo a riposo 90°
  • M666 servo in posizione 120° che aziona la penna
  • M777 servo in posizione 60° che aziona il cancellino
facendo partire PyCNC e lanciando uno dei comandi gcode sopra elencati il Raspberry invia dei segnali digitali ai pin precedentemente configurati.

nel file 
/PyCNC/cnc/gmachine.py
ho aggiunto le seguenti istruzioni

elif c == 'M333':  # Mirco - aziona i driver dei motori
            self._driver_on()
elif c == 'M444':  # Mirco - spegne i driver dei motori
            self._driver_off()
elif c == 'M666':  # Mirco - aziona la penna
            self._write()
elif c == 'M777':  # Mirco - aziona il cancellino
            self._erase()
elif c == 'M555':  # Mirco - posizione di riposo
            self._headup()
prendendo ad esempio il codice M666 sempre nello stesso file ho definito la funzione _write()
def _write(self):
        hal.write()
 e nel file
PyCNC/cnc/hal_raspberry/hal.py
 ho aggiunto la nuova funzione
def write():
    """ Abilito la penna con un output digitale al pin PEN_PIN
    """
    logging.info("aziona la penna")
    gpio.set(PEN_PIN)
    gpio.clear(ERASER_PIN)
In linea di massima queste sono le modifiche principali che ho apportato per i miei scopi.

Per lanciare PyCNC a linea di comando basta entrare nella directory PyCNC e digitare
sudo ./pycnc
pi@raspiboard:~/Desktop/iBoard/scripts/PyCNC $ cd /var/www/html/iBoard/scripts/PyCNC/
pi@raspiboard:/var/www/html/iBoard/scripts/PyCNC $ sudo ./pycnc
---- ads111x is not detected ----
*************** Welcome to iBoard! (powered by PyCNC) ***************
>
Dal momento che per azionare la penna o il cancellino servono comandi diversi dai classici M3 M5 sarà opportuno generare un gcode scritto ad hoc.
es. se vogliamo disegnare un quadrato il codice dovrà assomigliare a questo

M555
G0 X10 Y10
M666
G1 X10 Y20
G1 X20 Y20
G1 X20 Y10
G0 X10 Y10
M555
Ho collegato 2 motori al volo e fatto qualche test di funzionamento...



Arduino

Lato Arduino le cose sono molto più semplici perchè è sufficiente configurare dei pin in ingresso e leggerne il valore digitale.

Ipotizziamo questa configurazione:
Comando Gcode M666 configurato sul GPIO24 come uscita digitale del raspberry
pin GPIO24 collegato al PIN7 di Arduino

Quando digito l'istruzione Gcode M666 il Raspberry farà uscire un segnale digitale verso il PIN7 di Arduino, lo sketch di Arduino sa che quando arriva un segnale digitale sul PIN7 dovrà posizionare il servo sulla posizione 120° (poi riguardo alla posizione del servo ho avuti altri problemi di cui ne parlerò più avanti).

di seguito lo sketch che ho scritto e caricato su Arduino Uno
#include <Servo.h>
Servo myservo;
int pos = 0;
int inputEraser = 7;
int inputPen = 8;
int inputRele = 6;
int pinServo = 9;
int pinRele = 5;
int statusEraser = 0;
int statusPen = 0;
int statusRele = 0;
int servoVoidAngle = 90; // al momento non usato
int servoEraserAngle = 60; // al momento non usato
int servoPenAngle = 115; // al momento non usato
int current_angle = servoVoidAngle; // al momento non usato

int servoVoid_ms = 1750; // millisecondi per gestire la rotazione precisa a 90°
int servoEraser_ms = 1550; // millisecondi per gestire la rotazione precisa a 60°
int servoPen_ms = 1950; // millisecondi per gestire la rotazione precisa a 115°
int current_ms = servoVoid_ms;
String incomingByte = "";
void setup()
{
  pinMode(inputEraser, INPUT);
  pinMode(inputPen, INPUT);
  pinMode(inputRele, INPUT);
  pinMode(pinRele, OUTPUT);
  Serial.begin(9600);
  myservo.attach(pinServo);
}
void loop()
{
    if (Serial.available() > 0) {
         
            incomingByte = Serial.readString();
            if(incomingByte) {
              myservo.writeMicroseconds(incomingByte.toInt());
              Serial.println(incomingByte);
            }
    }
    if(true){
        statusEraser = digitalRead(inputEraser);
        statusPen = digitalRead(inputPen);
        statusRele = digitalRead(inputRele);
 
        if(statusRele==HIGH){
          digitalWrite(pinRele, LOW);
        }else{
          digitalWrite(pinRele, HIGH);
         }

        if(statusPen==HIGH || statusEraser==HIGH){
 if(statusPen==HIGH) {

            current_ms = servoPen_ms;
            myservo.writeMicroseconds(current_ms);
          }
          if(statusEraser==HIGH) {
            current_ms = servoEraser_ms;
            myservo.writeMicroseconds(current_ms);
          }
        }else{
          current_ms = servoVoid_ms;
          myservo.writeMicroseconds(current_ms);
        }
     
    }
}
Chi ha un pò di dimestichezza con gli sketch di Arduino avrà subito notato che per gestire la posizione del servo non ho specificato i gradi ma ho usato la funzione writeMicroseconds().
Il motivo di questa scelta è perchè quando specificavo una posizione di 90° il servo si posizionava a circa 80°, insomma non era preciso come volevo. La funzione writeMicroseconds permette di gestire la posizione in modo più accurato.

Il relè che avevo menzionato prima relativo alla gestione del risparmi di energia servirà per togliere corrente ai driver dei motori dopo un determinato periodo di inattività.
al momento il timer sul periodo di inattività non l'ho implementato nello sketch sopra ma lo farò più avanti a progetto concluso.


Conversione SVG -> Gcode

Per convertire un file SVG ci sono tanti modi e script opesource in giro per la rete e bene o male fanno tutti la stessa  cosa per cui invece di perdere tempo a "reinventare l'acqua calda" (riscrivendolo da zero) ne ho preso uno a caso su GitHub in Python e l'ho fatto diventare mio cambiando alcuni pezzi di codice per adattarlo allo scopo.

Lo script in questione si chiama svg2gcode ed è scaricabile da qui.
La prima cosa importante è editare il file config.py dove è possibile specificare l'area massima di lavoro e i prefissi e suffissi da applicare per ogni shape parsata.

questa qui sotto ad esempio è la configurazione che ho adottato io:
"""G-code emitted at the start of processing the SVG file"""
preamble = "g21\ng90\nm333\ng4 p1\ng28\nf9000"
"""G-code emitted at the end of processing the SVG file"""
postamble = "g4 p0.3"
"""G-code emitted before processing a SVG shape"""
shape_preamble = "g4 p0.1"
"""G-code emitted after processing a SVG shape"""
shape_postamble = "g4 p0.1\nm555"
"""Print bed width in mm"""
bed_max_x = 380
"""Print bed height in mm"""
bed_max_y = 220
"""
Used to control the smoothness/sharpness of the curves.
Smaller the value greater the sharpness. Make sure the
value is greater than 0.1
"""
smoothness = 0.1

Nel mio caso la massima estensione in X è 380 mm e in Y 220 mm, poi ho aggiunto i comandi M333 e M555 per attivare la corrente ai driver e per posizionare la testina a riposo più qualche altra piccola features nel preambolo iniziale.

Come dicevo poco fa anche in questa libreria mi sono trovato costretto ad apportare dei cambiamenti così ho fatto una copia del file chiamandola svg2gcodeMirco.py, questo sarà il file che chiamerò per generare il gcode adatto alle mie esigenze.

La parte che ho modificato è quella che si trova in fondo al file, in particolare ho aggiunto il comando M666, una pausa di 300ms (G4 p0.3) e un pò di commenti da inserire nel Gcode per fare debug.
print shape_preamble
p = point_generator(d, m, smoothness)
count = 1
    for x,y in p:
          if x > 0 and x < bed_max_x and y > 0 and y < bed_max_y:
                 if count == 2:
                        print "G4 p0.3\nM666\nG4 p0.3"
                        print "(startsegment)"
                        print "G1 X%0.1f Y%0.1f" % (scale_x*x, scale_y*y)
                        count += 1
                    else:
                        print "(fuori misure x%s y%s)" % (x,y)
                print "(endsegment)"
                print shape_postamble

Per convertire un file .svg in Gcode basta andare nella cartella principale dove si trovano i files di svg2gcode e lanciare questo comando
cat miofile.svg | python svg2gcode.py

il comando qui sopra "sputerà" a video il gcode appena generato per cui se lo vogliamo scrivere su un file basterà aggiungere in fondo il simbolo maggiore (>) ed il nome del file che vogliamo creare, es.
cat miofile.svg | python svg2gcode.py > miogcode.nc

Giunti a questo punto la strada è ormai in discesa perchè non resta altro che mettere insieme tutti i pezzi e farli lavorare a dovere.

Grecode

Generare il Gcode non basta perchè se ci pensate bene non è mai stato ancora specificato in che punto dell'area di lavoro dovrà essere posizionato il nostro disegno e oltre a questo nel gcode generato c'è un problema di codice specchiato nel senso che nel file SVG le coordinate provengono da quelle web e nella nostra macchina potrebbero non sempre coincidere.

Grecode è un'utile  libreria che si occupa di rimanipolare il Gcode ad esempio spostando il disegno in una coordinata specifica, specchiarlo, ruotarlo, scalarlo, strecciarlo e tanto altro.
Quindi dopo aver generato il Gcode è possibile decidere se darlo in pasto a grecode per applicare delle modifiche.


iBoard.class.php

Ho scritto questa classe PHP con il preciso compito di mettere insieme tutti i componenti descritti sopra e di farli lavorare all'unisono e comandare la lavagna.

La logica di funzionamento di questa classe è quello di generare un task (o job) per ogni disegno che viene fatto creando una cartella apposita con all'interno il singolo svg ed il Gcode generato.

Gestendo le cose in questo modo ho la possibilità di cancellare parzialmente la lavagna chiedendo la cancellazione di un preciso task.
Per la cancellazione parziale intendo che se ad esempio disegno una stella posso anche cancellarla senza dover passare tutta la lavagna da cima a fondo.

Come avviene la cancellazione parziale?
E' molto semplice, avendo il gcode salvato per ogni disegno quello che faccio è prendere le coordinate minime e massime del disegno parsando tutte le linee del gcode e costruendo al volo un altro file gcode che aziona il cancellino facendolo muovere a zigzag nell'area in cui si trovava il disegno.

Oltre a queste funzioni di base ne ho aggiunte altre per eseguire codice pre-formattato come ad esempio un messaggio di benvenuto o la cancellazione totale della lavagna.

esempio di cancellazione parziale della lavagna


easysvg (generatore testi svg in PHP)

easysvg è una classe PHP sempre scaricata da GitHub che permette di convertire un testo in SVG.

Qualcuno si starà chiedendo: ma perchè non generarli via web?

Il motivo è molto semplice, perchè generare via web un testo significa usare un apposito tag XML chiamato text all'interno del quale non sono presenti delle cordinate xy e quindi lo script svg2gcode non riuscirebbe a gestirlo.

Esiste una libreria Javascript (RaphaelJS) che manipola gli svg e che riesce a convertire un testo in path svg ma dopo alcune prove mi sono reso conto che è un pò pesante da gestire per il browser soprattutto in presenza di molto testo.

La soluzione che ho adottato è quella di inviare in POST alla mia classe iBoard.class.php solo il testo e qualche altro parametro come il font-family, il font-size, e l'allineamento, poi utilizzando la classe easysvg genero un svg da eseguire.
I font li genero con dei tool online che per mettono la conversione di un font .ttf in .svg creando quindi un webfont.

Se in un futuro troverò il modo per gestire in modo semplificato un testo in path svg lo implementerò e aggiornerò questo documento.

Il vantaggio di usare un generatore di testo svg in PHP è di automatizzare dei processi di scrittura sulla lavagna come ad esempio schedulare dei messaggi automatici tipo il meteo, qualche notizia presa via web o appuntamenti presi da Google Calendar.

usare easysvg è molto semplice
require 'easySVG.php';
$svg = new EasySVG();
$svg->setFont("om_telolet_om-webfont.svg", 100, '#000000');
$svg->addText("Simple text display");
$svg->addAttribute("width", "800px");
$svg->addAttribute("height", "120px");
echo $svg->asXML();

Console a linea di comando

Per poter gestire la scrittura automatica di testi ho sviluppato anche una console a linea di comando che utilizza sempre la classe iBoard.class.php ma che però può essere utilizzata in bash a linea di comando come ad esempio:
php controller/cli.php wtriteText -text="ciao!" -align=top-left -font=comic -size=40
l'istruzione qui sopra farà comparire sulla lavagna il testo "ciao!" alto 40 mm con il carattere comic posizionato in alto a sinistra.

Se volessi ad esempio schedulare la stampa delle ultime notizie principali prese da un feed RSS non serve altro che creare un CRON alle 8:00 di mattina che legge l'XML del feed RSS ed esegue il comando sopra  con il testo della notizia, poi se volendo potrei scaricare le previsioni meteo da open weather e stamparlo sotto alle notizie. L'unico limite è la fantasia...

Lato Client

Lato client sarà disponibile una interfaccia web HTML basata su jQuery che permetterà all'utente di scrivere del testo o disegnare a mano libera con il mouse o con il touch screen dello smartphone.
Ho sviluppato una piccola classe javascript che ha il compito di dialogare via Ajax con il web server inviando il disegno in formato SVG.



Disegno a mano libera




Scrittura di testi

Considerazioni

Il progetto tutto sommato si è concluso con successo senza particolari intoppi; l'aspetto sul quale devo lavorare ancora è legato al pennarello che con passare delle ore tende ad asciugarsi e quindi a non scrivere più.

Devo ancora fare dei test per capire se esiste una posizione di riposo tale per cui l'inchiostro non si secchi. Allo stato attuale quando il pennarello è a riposo rimane in una posizione inclinata con la punta rivolta leggermente verso l'alto e non credo sia molto vantaggiosa, dovrei provare a tenere la lavagna stesa su un pia in modo che il pennarello rimanga quasi in verticale.
Se anche così il pennarello si secca si potrebbe fare una modifica alla lavagna in modo che nella posizione di riposo a X0 Y0 sia presente una specie di foro che funge da tappo sul piano nel quale la punta della penna si possa infilare evitando di restare a contatto con l'aria.





Spero abbiate gradito questa presentazione, grazie per la lettura e alla prossima...

9 commenti:

  1. Progetto molto bello e articolato. Veramente complimenti per averlo sviluppato e portato a termine. Dubito che riuscirò a farlo ma sicuramente me lo studierò con attenzione. grazie per averlo condiviso. Saluti. Roberto

    RispondiElimina
  2. Invertire la posizione del pennarello magari ruotando il carrellino sotto sopra e un mini cappuccio automatico con lo stesso movimento del pennarello

    RispondiElimina
  3. ciao, scusami una domanda, ci sarebbe la possibilità di far andare tutto tramite bluetooth anzivhe wifi?

    RispondiElimina
    Risposte
    1. ciao, questo progetto è basato su un web server apache e necessita di una navigazione web per poter accedere all'interfaccia per cui tramite bluetooth non è possibile a meno che non si cambi tutto il software di comando.
      ciao

      Elimina
  4. Complimenti Mirko!
    Un lavoro fatastico, ben progettato e spiegato. Grazie per averlo condiviso.
    Non ho una printer 3D, ma vedrò come generare i pezzi. Alcuni li posso acquistare. Trovo particolarmente interessante la filosofia della semplicità e del box dal quale esce solo il cavo di alimentazione. A questo punto usato in verticale o in orizzontale non cambia, ma in verticale ottimizza incredibilmente gli spazi in workshop piccoli come il mio.

    Hai suggerimenti in caso io volessi cambiare le dimensioni? Disegno chitarre per cui ho bisogno di un'area di disegno utile di almeno 80x60. A parte gli ovvii cambi nelle parti meccaniche e nella configurazione del software non mi pare di vedere altri impedimenti.

    In alcuni casi potrei trovarmi ad avere già un file gcode in uscita da altri disegni. In quale parte del workflow credi potrei inserire manualmente il mio file, ammesso sia possibile? Altrimenti dovrò inventarmi qualcosa che funzioni come se lo avessi disegnato sul tablet.

    Seguo anche gli altri tuoi lavori. Sei una fonte di ispirazione costante. Grazie!
    Roberto

    RispondiElimina
    Risposte
    1. Ciao Roberto, praticamente quello che serve a te non è altro che un plotter giusto?
      Il sistema che ho realizzato alla fine dei conti è un plotter per ed il software che lo pilota è originariamente stato progetto per essere usato nelle CNC per cui se gli dai in pasto un Gcode funziona alla grande, anzi ho aggiunto nell'interfaccia la possibilità di caricare un Gcode. forse quest'ultima aggiunta non la troverai nel progetto da scaricare però se me lo chiedi te la invio via email.
      saluti

      Elimina
    2. Ciao Mirco, scusa il ritardo. Grazie 100 per la risposta, soprattutto perché è quella che mi aspettavo... :-)
      In effetti sì, a me occorre sostanzialmente un plotter. Magari un domani, sulla stessa meccanica potrei montare la testa per un laserino per fare piccole incisioni nel legno sfruttando le stesse logiche, ma per ora faccio tutto a mano una volta che ho i disegni.
      Inviami pure l'aggiornamento dell'interfaccia per fare upload diretto di un Gcode all'indirizzo: robertosciarra60@gmail.com
      Grazie 1000!
      Ciao!
      Roberto

      PS: vivo in UK, vicino a Liverpool, ma non fa una grossa differenza... :-)

      Elimina
  5. Wonderful work you have!!
    I have a little confusion in your wiring diagram :(
    Can you explain more about it? On how to connect each parts?
    Here is my email: dinhquoc2004@gmail.com
    Thanks a lot for your amazing project!

    RispondiElimina