Rodion Borisov
Published © CC BY-SA

CNC Flatbed Pen Plotter

Relatively cheap CNC plotter, that is directly controlled with G-code via own CAM software in PC. This is part of my graduation project.

IntermediateWork in progress29,018
CNC Flatbed Pen Plotter

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
USB A-B Cable
×1
5V 1.2A AC-to-DC Adapter
Should be plugged via 2.1mm center-positive plug to the Arduino's power jack.
×1
Stepper Motor 28BYJ-48 - 5V
×4
Driver PCB based on ULN2003A
It is useful for driving unipolar stepper motors. Works like digital amplifier.
×4
M6 Coupling Nut 10 mm Long
Needed to fix rod with motor's shaft.
×4
M6 Threaded Rod
1 meter is just fine.
×1
Universal breadboard SYB-46
Solderless technologies!
×1
20cm Male-to-Male Jumper Wire Cable 2.54mm
×20
20cm Male-to-Female Jumper Wire Cable 2.54mm
×40

Software apps and online services

Arduino IDE
Arduino IDE
AccelStepper library for Arduino
This library provides an object-oriented interface for 2, 3 or 4 pin stepper motors and motor drivers.
Inkscape
Extensible vector graphics editor with Python 2.7.* included. Needed to write our own CAM extension.
Gcodetools plug-in for Inkscape
Needed to convert vector image to good G-code.

Hand tools and fabrication machines

Vernier Caliper
Needed for precise and convenient meter measurement.
Electric Drill
As alternative, electric screwdriver comes handy, but it's not recommended.
M5 Metal Drill Bit
Needed for making holes in movable weights for threading.
M6 Metalworking Drill Tap
Needed for threading in these weights.
M2 Metal Drill Bit
Needed for making holes in long nuts.
M3 Metalworking Drill Tap
Needed for threading in these nuts.
Angle Grinder
Needed for cutting and chamfering of threaded rod with use of cut-off wheel.
Cut-off Wheel
Mechanical Pencil 0.5 mm
Or use any other pen (preferably with very liquid ink).
Solid (metallic or wooden) flat weight with size of 1" approx.
https://www.hackster.io/VINTproYKT/cnc-flatbed-pen-plotter-1780c9/logs/2

Story

Read more

Schematics

Fritzing schematic

PDF schematic

Code

Apparatus code

Arduino
Upload this code to Arduino board.
/*
  CNC Flatbed Pen Plotter
  https://create.arduino.cc/vintproykt/cnc-flatbed-pen-plotter-1780c9
*/

#include <AccelStepper.h>
#include <MultiStepper.h>

#define MOTORS_MAXSPEED 1500
#define MOTORS_ACCELERATION 100
#define MOTORS_STEPS_PER_REVOLUTION 4096 // 28BYJ-48 in half-step mode

AccelStepper motorX(AccelStepper::HALF4WIRE, 2, 3, 4, 5);
AccelStepper motorY(AccelStepper::HALF4WIRE, 6, 7, 8, 9);
AccelStepper motorZ(AccelStepper::HALF4WIRE, 10, 11, 12, 13);

MultiStepper motors;

short motors_dir = 1;
int motors_avgSpeed = MOTORS_MAXSPEED;// Average speed

String input = "";

void doCommand(String command, String param) {// Serial commands hub
  if (command == "go") {
    long steps = param.toInt();
    if (steps == 0) steps = MOTORS_STEPS_PER_REVOLUTION;// Make full revolution by default
    _go(steps);
  }
  else if (command == "stop") _stop();
  else if (command == "dir") _dir();
  else if (command == "speed") {
    float speed = param.toInt();
    if (speed == 0) speed = MOTORS_MAXSPEED;// Average speed equals maximum speed by default
    _speed(speed);
  }
}

void setup() {
  Serial.begin(115200);// Maximum baud rate for Arduino Uno
  Serial.println("Запуск");
  
  input.reserve(128);
  
  motorX.setMaxSpeed(MOTORS_MAXSPEED);
  motorY.setMaxSpeed(MOTORS_MAXSPEED);
  motorZ.setMaxSpeed(MOTORS_MAXSPEED);
  motorX.setAcceleration(MOTORS_ACCELERATION);
  motorY.setAcceleration(MOTORS_ACCELERATION);
  motorZ.setAcceleration(MOTORS_ACCELERATION);
  motors.addStepper(motorX);
  motors.addStepper(motorY);
  motors.addStepper(motorZ);
}

void loop() {
  while (Serial.available()) {
    input = Serial.readStringUntil('\n');
    input.trim();
    int input_sp = input.indexOf(' ');// Checking for space character in input string
    String input_command = input;
    String input_param;
    if (input_sp > 0) {
      input_command = input.substring(0, input_sp);
      input_param = input.substring(input_sp + 1);
      input_param.trim();
    }
    doCommand(input_command, input_param);
    input = "";
  }
  
  measureSteps();
  
  motors.run();
}

void _go(long increment) {
  if (motorX.speed() == 0) {
    motorX.setSpeed(motors_avgSpeed);
    motorY.setSpeed(motors_avgSpeed);
    motorZ.setSpeed(motors_avgSpeed);
    motors.moveTo(motorX.currentPosition() + motors_dir * increment);
    Serial.print("Move to ");
    Serial.print(motorX.targetPosition());
    Serial.print(" (rotate by ");
    Serial.print((float)increment / (float)MOTORS_STEPS_PER_REVOLUTION * 360);
    Serial.print("° ");
    if (motors_dir < 0) Serial.print("counter");
    Serial.print("clockwise");
    Serial.println(")");
  }
}

void _stop() {
  motors.moveTo(motorX.currentPosition());
  motorX.setSpeed(0);
  motorY.setSpeed(0);
  motorZ.setSpeed(0);
  motorX.stop();
  motorY.stop();
  motorZ.stop();
  Serial.println("Stopped");
}

void _dir() {
  motors_dir = -motors_dir;
  if (motors_dir > 0) Serial.println("CW");
  else Serial.println("CCW");
}

void _speed(float speed) {
  motors_avgSpeed = speed;
  Serial.print("Average speed changed to ");
  Serial.println(speed);
}

void measureSteps() {
  if (motorX.speed() != 0) {
    Serial.print("Position: ");
    Serial.print(motorX.currentPosition());
    Serial.print(" | Speed: ");
    Serial.print(motorX.speed());
    Serial.println(" steps/s");
  }
}

Credits

Rodion Borisov

Rodion Borisov

1 project • 16 followers
Thanks to Anton Uzlov, Anatoliy Proshutinskiy, Sergey Filippov, and Igor Krymov.

Comments