Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D

Componentes y materiales

Arduino UNO (cerebro) ×1
Shield L293D Motor Driver (controla steppers X/Y) ×1
Servo Tower Pro 9g (eje Z: pluma arriba/abajo) ×1
Unidad DVD reciclada (mecánica X e Y) ×1
Cables jumpers ×1

Aplicaciones y servicios online

Sobre el proyecto

Montaje mecánico

Desarma dos unidades DVD y extrae las bandejas internas con su mecanismo stepper: serán ejes X e Y. Perfora la carcasa vacía para montar cada eje con tornillos. Colócalos perpendiculares.

Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D
  1. Descarga Arduino IDE.
  2. Descarga Processing IDE.
  3. Abre Arduino IDE y carga el sketch Arduino CNC (ver sección Código).
  4. Abre Processing IDE y carga el sketch Processing G-code sender (ver Código).

Generar G-code con Inkscape

Inkscape (gratis, open-source, Win/Mac/Linux) convierte gráficos vectoriales (SVG) a G-code.

  1. Instala Inkscape versión 0.48.5 (importante: versiones nuevas cambian la extensión).
  2. Instala add-on G-code export (con instrucciones).
  3. Sigue tutorial en YouTube para crear archivo G-code.

Usar el plotter

  1. Sube sketch Processing y pulsa Play.
  2. Pulsa 'p' → selecciona puerto serie.
  3. Opcional: '1'/'2'/'3' = velocidad jog (1/10/100 mils).
  4. Pulsa 'g' → carga archivo G-code.
  5. Enter → ¡empieza a dibujar!

Archivos G-code de prueba:

Ver ilustración completa en el enlace del proyecto original.

Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D
Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D
Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D
Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D
Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D
Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D
Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D

Código

Sketch Arduino (CNC)

#include <Servo.h>
#include <AFMotor.h>

#define LINE_BUFFER_LENGTH 512
char STEP = MICROSTEP;

const int penZUp = 95, penZDown = 83;
const int penServoPin = 10;
const int stepsPerRevolution = 48;

Servo penServo;
AF_Stepper myStepperY(stepsPerRevolution, 1);
AF_Stepper myStepperX(stepsPerRevolution, 2);

struct point { float x, y, z; };
point actuatorPos;

float StepInc = 1, StepDelay = 0, LineDelay = 0, penDelay = 50;
float StepsPerMillimeterX = 100.0, StepsPerMillimeterY = 100.0;
float Xmin = 0, Xmax = 40, Ymin = 0, Ymax = 40, Zmin = 0, Zmax = 1;
float Xpos = Xmin, Ypos = Ymin, Zpos = Zmax;
boolean verbose = false;

// Interpreta: G0/G1 movimiento, G4 espera, M300 S30 pluma abajo, M300 S50 pluma arriba
void setup() {
  Serial.begin(9600);
  penServo.attach(penServoPin);
  penServo.write(penZUp);
  delay(100);
  myStepperX.setSpeed(600);
  myStepperY.setSpeed(600);
  Serial.println("Mini CNC Plotter alive and kicking!");
  Serial.print("X range: "); Serial.print(Xmin); Serial.print(" to "); Serial.print(Xmax); Serial.println(" mm.");
  Serial.print("Y range: "); Serial.print(Ymin); Serial.print(" to "); Serial.print(Ymax); Serial.println(" mm.");
}

void loop() {
  delay(100);
  char line[LINE_BUFFER_LENGTH], c;
  int lineIndex = 0;
  bool lineIsComment = false, lineSemiColon = false;

  while (1) {
    while (Serial.available() > 0) {
      c = Serial.read();
      if (c == '\n' || c == '\r') {
        if (lineIndex > 0) {
          line[lineIndex] = '\0';
          if (verbose) { Serial.print("Received: "); Serial.println(line); }
          processIncomingLine(line, lineIndex);
          lineIndex = 0;
        }
        lineIsComment = lineSemiColon = false;
        Serial.println("ok");
      } else {
        if (lineIsComment || lineSemiColon) {
          if (c == ')') lineIsComment = false;
        } else if (c <= ' ') { /* ignore */ }
        else if (c == '/') { /* ignore */ }
        else if (c == '(') { lineIsComment = true; }
        else if (c == ';') { lineSemiColon = true; }
        else if (lineIndex >= LINE_BUFFER_LENGTH - 1) {
          Serial.println("ERROR - lineBuffer overflow");
          lineIsComment = lineSemiColon = false;
        } else if (c >= 'a' && c <= 'z') {
          line[lineIndex++] = c - 'a' + 'A';
        } else {
          line[lineIndex++] = c;
        }
      }
    }
  }
}

void processIncomingLine(char* line, int charNB) {
  int currentIndex = 0;
  char buffer[64];
  point newPos = {0, 0, 0};

  while (currentIndex < charNB) {
    switch (line[currentIndex++]) {
      case 'U': penUp(); break;
      case 'D': penDown(); break;
      case 'G':
        buffer[0] = line[currentIndex++];
        buffer[1] = '\0';
        switch (atoi(buffer)) {
          case 0: case 1: { // G0/G1
            char* indexX = strchr(line + currentIndex, 'X');
            char* indexY = strchr(line + currentIndex, 'Y');
            if (!indexY) { newPos.x = atof(indexX + 1); newPos.y = actuatorPos.y; }
            else if (!indexX) { newPos.y = atof(indexY + 1); newPos.x = actuatorPos.x; }
            else { newPos.y = atof(indexY + 1); *indexY = '\0'; newPos.x = atof(indexX + 1); }
            drawLine(newPos.x, newPos.y);
            actuatorPos.x = newPos.x; actuatorPos.y = newPos.y;
            break; }
        }
        break;
      case 'M':
        buffer[0] = line[currentIndex++];
        buffer[1] = line[currentIndex++];
        buffer[2] = line[currentIndex++];
        buffer[3] = '\0';
        switch (atoi(buffer)) {
          case 300: {
            char* indexS = strchr(line + currentIndex, 'S');
            float Spos = atof(indexS + 1);
            if (Spos == 30) penDown();
            if (Spos == 50) penUp();
            break; }
          case 114: // M114 report position
            Serial.print("Absolute position: X = "); Serial.print(actuatorPos.x);
            Serial.print(" - Y = "); Serial.println(actuatorPos.y);
            break;
          default:
            Serial.print("Command not recognized: M"); Serial.println(buffer);
        }
    }
  }
}

void drawLine(float x1, float y1) {
  if (x1 >= Xmax) x1 = Xmax;
  if (x1 <= Xmin) x1 = Xmin;
  if (y1 >= Ymax) y1 = Ymax;
  if (y1 <= Ymin) y1 = Ymin;

  long x0 = (long)(Xpos * StepsPerMillimeterX);
  long y0 = (long)(Ypos * StepsPerMillimeterY);
  x1 = (long)(x1 * StepsPerMillimeterX);
  y1 = (long)(y1 * StepsPerMillimeterY);

  long dx = abs(x1 - x0), dy = abs(y1 - y0);
  int sx = (x0 < x1) ? StepInc : -StepInc;
  int sy = (y0 < y1) ? StepInc : -StepInc;
  long i, over = 0;

  if (dx > dy) {
    for (i = 0; i < dx; ++i) {
      myStepperX.onestep(sx, STEP);
      over += dy;
      if (over >= dx) { over -= dx; myStepperY.onestep(sy, STEP); }
      delay(StepDelay);
    }
  } else {
    for (i = 0; i < dy; ++i) {
      myStepperY.onestep(sy, STEP);
      over += dx;
      if (over >= dy) { over -= dy; myStepperX.onestep(sx, STEP); }
      delay(StepDelay);
    }
  }
  delay(LineDelay);
  Xpos = x1 / StepsPerMillimeterX;
  Ypos = y1 / StepsPerMillimeterY;
}

void penUp() {
  penServo.write(penZUp);
  delay(penDelay);
  Zpos = Zmax;
  digitalWrite(15, LOW); digitalWrite(16, HIGH);
  if (verbose) Serial.println("Pen up!");
}

void penDown() {
  penServo.write(penZDown);
  delay(penDelay);
  Zpos = Zmin;
  digitalWrite(15, HIGH); digitalWrite(16, LOW);
  if (verbose) Serial.println("Pen down.");
}

Sketch Processing (G-code sender)

import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;
import processing.serial.*;

Serial port = null;
String portname = null;  // null = interactivo (tecla 'p')
boolean streaming = false;
float speed = 0.001;
String[] gcode;
int i = 0;

void openSerialPort() {
  if (portname == null) return;
  if (port != null) port.stop();
  port = new Serial(this, portname, 9600);
  port.bufferUntil('\n');
}

void selectSerialPort() {
  String result = (String) JOptionPane.showInputDialog(frame,
    "Select the serial port for your Arduino.", "Select serial port",
    JOptionPane.QUESTION_MESSAGE, null, Serial.list(), 0);
  if (result != null) { portname = result; openSerialPort(); }
}

void setup() {
  size(500, 250);
  openSerialPort();
}

void draw() {
  background(0); fill(255);
  int y = 24, dy = 12;
  text("INSTRUCCIONES", 12, y); y += dy;
  text("p: seleccionar puerto serie", 12, y); y += dy;
  text("1: velocidad 0.001 pulg/paso", 12, y); y += dy;
  text("2: velocidad 0.010 pulg/paso", 12, y); y += dy;
  text("3: velocidad 0.100 pulg/paso", 12, y); y += dy;
  text("flechas: jog X-Y", 12, y); y += dy;
  text("RePag/AvPag: jog Z", 12, y); y += dy;
  text("$: mostrar ajustes GRBL", 12, y); y += dy;
  text("h: ir a home (0,0,0)", 12, y); y += dy;
  text("0: cero máquina (home = posición actual)", 12, y); y += dy;
  text("g: enviar archivo G-code", 12, y); y += dy;
  text("x: detener envío G-code (no inmediato)", 12, y); y += dy;
  y = height - dy;
  text("velocidad jog actual: " + speed + " pulg/paso", 12, y); y -= dy;
  text("puerto serie actual: " + portname, 12, y);
}

void keyPressed() {
  if (key == '1') speed = 0.001;
  if (key == '2') speed = 0.01;
  if (key == '3') speed = 0.1;

  if (!streaming) {
    if (keyCode == LEFT)  port.write("G91\nG20\nG00 X-" + speed + " Y0.000 Z0.000\n");
    if (keyCode == RIGHT) port.write("G91\nG20\nG00 X"  + speed + " Y0.000 Z0.000\n");
    if (keyCode == UP)    port.write("G91\nG20\nG00 X0.000 Y"  + speed + " Z0.000\n");
    if (keyCode == DOWN)  port.write("G91\nG20\nG00 X0.000 Y-" + speed + " Z0.000\n");
    if (keyCode == KeyEvent.VK_PAGE_UP)   port.write("G91\nG20\nG00 X0.000 Y0.000 Z"  + speed + "\n");
    if (keyCode == KeyEvent.VK_PAGE_DOWN) port.write("G91\nG20\nG00 X0.000 Y0.000 Z-" + speed + "\n");
    if (key == 'h') port.write("G90\nG20\nG00 X0.000 Y0.000 Z0.000\n");
    if (key == 'v') port.write("$0=75\n$1=74\n$2=75\n");
    if (key == 's') port.write("$3=10\n");
    if (key == 'e') port.write("$16=1\n");
    if (key == 'd') port.write("$16=0\n");
    if (key == '0') openSerialPort();
    if (key == 'p') selectSerialPort();
    if (key == '$') port.write("$$\n");
  }

  if (!streaming && key == 'g') {
    gcode = null; i = 0;
    println("Cargando archivo...");
    selectInput("Selecciona archivo G-code:", "fileSelected", null);
  }
  if (key == 'x') streaming = false;
}

void fileSelected(File selection) {
  if (selection == null) { println("Cancelado."); return; }
  println("Archivo: " + selection.getAbsolutePath());
  gcode = loadStrings(selection.getAbsolutePath());
  if (gcode == null) return;
  streaming = true;
  stream();
}

void stream() {
  if (!streaming) return;
  while (true) {
    if (i == gcode.length) { streaming = false; return; }
    if (gcode[i].trim().length() == 0) i++;
    else break;
  }
  println(gcode[i]);
  port.write(gcode[i] + '\n');
  i++;
}

void serialEvent(Serial p) {
  String s = p.readStringUntil('\n');
  println(s.trim());
  if (s.trim().startsWith("ok") || s.trim().startsWith("error")) stream();
}

Esquemático

Conecta todos los componentes como se muestra:
Mini plotter CNC 2D casero con unidades de DVD recicladas y shield L293D

Proceso de manufactura

  1. Construye tu propia máquina de escribir deberes casera (DIY Homework Writing Machine)
  2. Crea un Impresionante Sistema Ambilight para Monitor con Arduino
  3. Robot de Detección Humana con Arduino Uno: Integración de Sensores Paso a Paso
  4. Vehículo Controlado por Android con Raspberry Pi, Arduino y Motor Shield: Guía Completa
  5. Crea un Botón de Teclado Personalizado y "Apuñalable" con Arduino: Guía Paso a Paso
  6. Mide la masa de la Tierra con Arduino: Guía paso a paso DIY
  7. Crea una Interfaz Web en PHP para Controlar tu Arduino Uno
  8. Genera Tonos Musicales con Arduino: Guía Paso a Paso
  9. Puerta automática con Arduino y sensor ultrasónico HC-SR04
  10. Construye un Coche Bluetooth Controlado con Arduino Nano: Guía DIY Completa
  11. Construye una Brújula Digital en Tiempo Real con Arduino y Processing