Buy Aruino   Buy Arduino Uno on AliExpress

CNC Plotter

Well If a layman asks you what is CNC Plotter then what will you answer him?

In our case, CNC Pen Plotter is a device that is used to write on the paper. It will use a stepper motor to give the motion to the paper and pen to write on the paper. It is a low-cost project.

Hardware Required

  • Arduino Board
  • 2*Stepper Motors
  • 1*Servo Motors
  • 2*L293D IC
  • BreadBoard / PCB
  • Jumper Wire ( Male*Male ) \ Hook up Wire

Stepper Motors can be obtained from the CD-ROM of your CPU. The Servo motor which I suggest you to buy from Amazon as it offers good quality products at low prices.

CD-ROM

The first step towards this project would be opening your CD-ROM and taking out stepper motors. You need to use the screwdrivers to open the screws before you reach of your stepper motor. There would be three motors inside the CD-ROM but there is only one stepper motor.

Circuit Diagram

Although our next step should have been how to assemble those CD-ROMs at the 90-degree angle but I prefer making connections first so as to confirm that all things are working.

We would be joining our all components together wither it would be solderless breadboard or PCB (Printed Circuit Board). I recommend you to read the datasheet of the IC at first which would give you an overview of how wires are connected. I personally read the datasheet of the IC before making my own plotter which was quite beneficial.

You need to connect wires according to the given circuit diagram. At first, you may use only one IC and don't connect the other servo and stepper. Just check this one stepper motor and the other on the same IC.

One thing you need to keep in mind that most stepper motors require 5V - 1 Amp Current. So please take care of that. I recommend you to not use the battery for this purpose. You may use your mobile charger for this purpose. As some of them supply the 5v - 1 amp Current. Don’t worry if the current value is slightly increasing or decreasing , it wouldn’t affect that much.

Assembly

We are finished with our circuits, now its time for mounting the stepper motors at the right angle. They should be aligned at the 90 degree so as the pen may move smoothly on the cardboard. Otherwise, there would be two cases:

  1. Pen won’t be writing all over the paper.
  2. There would be a lot of pressure exerted on the pen which may de-attach your pen from its position.

If I talk on how to stick those two at the 90-degree angle. then there are several ways in which you can do it. It is like asking a person ”how to put the food into the mouth”. The answer would be "it depends on your creativity".

If you have proper tools for Drilling and you have different kinds of adhesives and all that then you should go for drilling and all that purpose to make your project perfect. For those who don’t have that can use their simple mechanisms like I used sharpeners to stick those with a cheap adhesive.

You have to stick cardboard to one stepper motor which would be at the bottom. As later on, you would be placing the papers on it for printing. The length of cardboard would be 5,5 cm or might differ depending on the size of the rails.

Coding

The Coding Part is the most difficult part for beginners as the code used for this program is consists of 412 lines of code. Here is the code you need to upload to your Arduino Board.

/*
Mini CNC Plotter firmware, based in TinyCNC http://github.com/MakerBlock/TinyCNC-Sketches
Send GCODE to this Sketch using gctrl.pde http://github.com/damellis/gctrl
Convert SVG to GCODE with MakerBot Unicorn plugin for Inkscape available here http://github.com/martymcguire/inkscape-unicorn

*/

#include <Servo.h>
#include <Stepper.h>

#define LINE_BUFFER_LENGTH 512

// Servo position for Up and Down
const int penZUp = 80;
const int penZDown = 40;

// Servo on PWM pin 6
const int penServoPin = 6;

// Should be right for DVD steppers, but is not too important here
const int stepsPerRevolution = 20;

// create servo object to control a servo
Servo penServo;

// Initialize steppers for X- and Y-axis using this Arduino pins for the L293D H-bridge
Stepper myStepperY(stepsPerRevolution, 2,3,4,5);
Stepper myStepperX(stepsPerRevolution, 8,9,10,11);

/* Structures, global variables */
struct point {
float x;
float y;
float z;
};

// Current position of plothead
struct point actuatorPos;

// Drawing settings, should be OK
float StepInc = 1;
int StepDelay = 0;
int LineDelay = 50;
int penDelay = 50;

// Motor steps to go 1 millimeter.
// Use test sketch to go 100 steps. Measure the length of line.
// Calculate steps per mm. Enter here.
float StepsPerMillimeterX = 6;
float StepsPerMillimeterY = 6;

// Drawing robot limits, in mm
// OK to start with. Could go up to 50 mm if calibrated well.
float Xmin = 0;
float Xmax = 40;
float Ymin = 0;
float Ymax = 40;
float Zmin = 0;
float Zmax = 1;

float Xpos = Xmin;
float Ypos = Ymin;
float Zpos = Zmax;

// Set to true to get debug output.
boolean verbose = false;

// Needs to interpret
// G1 for moving
// G4 P300 (wait 150ms)
// M300 S30 (pen down)
// M300 S50 (pen up)
// Discard anything with a (
// Discard any other command!

/**********************
* void setup() – Initialisations
***********************/
void setup() {
// Setup
Serial.begin( 9600 );

penServo.attach(penServoPin);
penServo.write(penZUp);
delay(200);

// Decrease if necessary
myStepperX.setSpeed(250);
myStepperY.setSpeed(250);

// Set & move to initial default position
// TBD

// Notifications!!!
Serial.println(“Mini CNC Plotter alive and kicking!”);
Serial.print(“X range is from “);
Serial.print(Xmin);
Serial.print(” to “);
Serial.print(Xmax);
Serial.println(” mm.”);
Serial.print(“Y range is from “);
Serial.print(Ymin);
Serial.print(” to “);
Serial.print(Ymax);
Serial.println(” mm.”);
}

/**********************
* void loop() – Main loop
***********************/
void loop()
{
delay(200);
char line[ LINE_BUFFER_LENGTH ];
char c;
int lineIndex;
bool lineIsComment, lineSemiColon;

lineIndex = 0;
lineSemiColon = false;
lineIsComment = false;

while (1) {

// Serial reception – Mostly from Grbl, added semicolon support
while ( Serial.available()>0 ) {
c = Serial.read();
if (( c == ‘\n’) || (c == ‘\r’) ) { // End of line reached
if ( lineIndex > 0 ) { // Line is complete. Then execute!
line[ lineIndex ] = ‘\0’; // Terminate string
if (verbose) {
Serial.print( “Received : “);
Serial.println( line );
}
processIncomingLine( line, lineIndex );
lineIndex = 0;
}
else {
// Empty or comment line. Skip block.
}
lineIsComment = false;
lineSemiColon = false;
Serial.println(“ok”);
}
else {
if ( (lineIsComment) || (lineSemiColon) ) { // Throw away all comment characters
if ( c == ‘)’ ) lineIsComment = false; // End of comment. Resume line.
}
else {
if ( c <= ‘ ‘ ) { // Throw away whitepace and control characters
}
else if ( c == ‘/’ ) { // Block delete not supported. Ignore character.
}
else if ( c == ‘(‘ ) { // Enable comments flag and ignore all characters until ‘)’ or EOL.
lineIsComment = true;
}
else if ( c == ‘;’ ) {
lineSemiColon = true;
}
else if ( lineIndex >= LINE_BUFFER_LENGTH-1 ) {
Serial.println( “ERROR – lineBuffer overflow” );
lineIsComment = false;
lineSemiColon = false;
}
else if ( c >= ‘a’ && c <= ‘z’ ) { // Upcase lowercase
line[ lineIndex++ ] = c-‘a’+’A’;
}
else {
line[ lineIndex++ ] = c;
}
}
}
}
}
}

void processIncomingLine( char* line, int charNB ) {
int currentIndex = 0;
char buffer[ 64 ]; // Hope that 64 is enough for 1 parameter
struct point newPos;

newPos.x = 0.0;
newPos.y = 0.0;

// Needs to interpret
// G1 for moving
// G4 P300 (wait 150ms)
// G1 X60 Y30
// G1 X30 Y50
// M300 S30 (pen down)
// M300 S50 (pen up)
// Discard anything with a (
// Discard any other command!

while( currentIndex < charNB ) {
switch ( line[ currentIndex++ ] ) { // Select command, if any
case ‘U’:
penUp();
break;
case ‘D’:
penDown();
break;
case ‘G’:
buffer[0] = line[ currentIndex++ ]; // /!\ Dirty – Only works with 2 digit commands
// buffer[1] = line[ currentIndex++ ];
// buffer[2] = ‘\0’;
buffer[1] = ‘\0’;

switch ( atoi( buffer ) ){ // Select G command
case 0: // G00 & G01 – Movement or fast movement. Same here
case 1:
// /!\ Dirty – Suppose that X is before Y
char* indexX = strchr( line+currentIndex, ‘X’ ); // Get X/Y position in the string (if any)
char* indexY = strchr( line+currentIndex, ‘Y’ );
if ( indexY <= 0 ) {
newPos.x = atof( indexX + 1);
newPos.y = actuatorPos.y;
}
else if ( indexX <= 0 ) {
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 );
// Serial.println(“ok”);
actuatorPos.x = newPos.x;
actuatorPos.y = newPos.y;
break;
}
break;
case ‘M’:
buffer[0] = line[ currentIndex++ ]; // /!\ Dirty – Only works with 3 digit commands
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);
// Serial.println(“ok”);
if (Spos == 30) {
penDown();
}
if (Spos == 50) {
penUp();
}
break;
}
case 114: // M114 – Repport 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 );
}
}
}

}
/*********************************
* Draw a line from (x0;y0) to (x1;y1).
* Bresenham algo from http://www.marginallyclever.com/blog/2013/08/how-to-build-an-2-axis-arduino-cnc-gcode-interpreter/
* int (x1;y1) : Starting coordinates
* int (x2;y2) : Ending coordinates
**********************************/
void drawLine(float x1, float y1) {

if (verbose)
{
Serial.print(“fx1, fy1: “);
Serial.print(x1);
Serial.print(“,”);
Serial.print(y1);
Serial.println(“”);
}

// Bring instructions within limits
if (x1 >= Xmax) {
x1 = Xmax;
}
if (x1 <= Xmin) {
x1 = Xmin;
}
if (y1 >= Ymax) {
y1 = Ymax;
}
if (y1 <= Ymin) {
y1 = Ymin;
}

if (verbose)
{
Serial.print(“Xpos, Ypos: “);
Serial.print(Xpos);
Serial.print(“,”);
Serial.print(Ypos);
Serial.println(“”);
}

if (verbose)
{
Serial.print(“x1, y1: “);
Serial.print(x1);
Serial.print(“,”);
Serial.print(y1);
Serial.println(“”);
}// Convert coordinates to steps
x1 = (int)(x1*StepsPerMillimeterX);
y1 = (int)(y1*StepsPerMillimeterY);
float x0 = Xpos;
float y0 = Ypos;

// Let’s find out the change for the coordinates
long dx = abs(x1-x0);
long dy = abs(y1-y0);
int sx = x0<x1 ? StepInc : -StepInc;
int sy = y0<y1 ? StepInc : -StepInc;

long i;
long over = 0;

if (dx > dy) {
for (i=0; i<dx; ++i) {
myStepperX.step(sx);
over+=dy;
if (over>=dx) {
over-=dx;
myStepperY.step(sy);
}
delay(StepDelay);
}
}
else {
for (i=0; i<dy; ++i) {
myStepperY.step(sy);
over+=dx;
if (over>=dy) {
over-=dy;
myStepperX.step(sx);
}
delay(StepDelay);
}
}

if (verbose)
{
Serial.print(“dx, dy:”);
Serial.print(dx);
Serial.print(“,”);
Serial.print(dy);
Serial.println(“”);
}

if (verbose)
{
Serial.print(“Going to (“);
Serial.print(x0);
Serial.print(“,”);
Serial.print(y0);
Serial.println(“)”);
}

// Delay before any next lines are submitted
delay(LineDelay);
// Update the positions
Xpos = x1;
Ypos = y1;
}

// Raises pen
void penUp() {
penServo.write(penZUp);
delay(LineDelay);
Zpos=Zmax;
if (verbose) {
Serial.println(“Pen up!”);
}
}
// Lowers pen
void penDown() {
penServo.write(penZDown);
delay(LineDelay);
Zpos=Zmin;
if (verbose) {
Serial.println(“Pen down.”);
}
}

After Uploading this code next part is to use the gctrl. The gctrl is application used to give Commands to your Arduino to draw images from the gcode file. It is like you are passing some instructions to gctrl and then it would pass to Arduino.

To use gctrl you need to have processing software as gctrl is nothing but a program written for processing. Like you write program in Turbo C++.

Here is the links to all the files:

Now, what you need to do is:

  • Upload Code to Arduino
  • Install Processing ( optional )
  • Open gctrl
  • Run gctrl
  • Select Port and Select your gcode file
  • You can select drawing .gcode file which i have provided above

How to Create your own Gcode file

To create your own gcode files you need to use the ink space software.

Download and install Inkscape from here (Important: download 0.48.5 version).

Now you need to install an Add-on that enables the export images to gcode files. This add on can be found here with installation notes.

Setup Inkscape for first use

Open the Inkscape, go to File menu and click “Document Properties”. See the 1st image above and make the changes, make sure to change first to “cm”. Now close this window.

We will use the area within 4 to 8 cm. See the 2nd image above.

How to print texts

Put text, change the font to Times New Roman and size to 22. Now click on cursor icon and center the text like the 3rd image above. Select Path from the menu and “Object to Path”.

How to print images

This is more difficult than texts. Images must have a transparent background. Drag and drop the Arduino logo image (download it from files) in Inkscape. Click ok to the next window. Now you have to re-size the image to fit our printing area, see the 4th image above. Click Path from menu and “Trace Bitmap”.

Make changes as the 5th image above. Click ok and close the window. Now, move the grayscale image, and delete the color one behind it. Move the grey image to the correct place again and click from the Path menu “Object to path”.

Export as gcode

Final, go to file menu, click save as and select .gcode. Click ok on the next window. That’s it! Ready to go! Use the gctrl.pde app to print the gcode file on your new Arduino CNC Plotter!

Here you are completed with your CNC Plotter. Share the images or videos of your plotter. I would be happy to see those. Feel free to contact me in case of any queries.

Ардуино+