Introduction: Arduino Mini CNC Plotter Machine From Dvd Drives

In this project I will show you how to easily build your own low-cost Arduino Mini CNC Plotter!

This project is an update from my previous cnc, with better construction and with more accuracy.

I decided to make this detailed guide to help you make it on a few easy steps.

Small description:

For the X and Y axes we will use two stepper motors and rails from dvd/cd drives and for the Z axis we will use a small servo motor that moves the pen up and down. For the mounting base we will use a small piece of plexiglass.

You can easily attach a pen (or pencil) - irrespective of its thickness - on it. I tried to use an extension of cutting tool (e.g.Dremel) to engrave materials with no success. So this mini cnc can only be used as a small plotter and not as an engraver machine.

The Arduino-based circuit is using the ATmega328 microcontroller, two L293 motor driver ICs and an usb to serial module. You can easily make it with the Arduino uno board and an breadboard.

You can also use an Bluetooth module (e.g. HC-06) to print your texts (or images) wirelessly through your computer Bluetooth connection! Pretty cool huh?

Q & A and updates here: http://www.ardumotive.com/new-cnc-plotter.html

More cool Arduino projects can be found here: www.ardumotive.com

Watch presentation video below and proceed to next step!

Follow us on FB: https://www.facebook.com/ardumotive
Follow us on Twitter: https://twitter.com/ardumotive

YouTube channel

Step 1: What You Will Need

Tip: See the images above.

Visit and buy your hardware from www.gearbest.com

For the circuit you will need:

Part list for beginners:

  • Arduino uno
  • Breadboard
  • 2x L293D ICs Motor driver
  • Mini Servo Motor
  • 2x DVD/CD Drives

Part list for 'pro' :

  • ATmega328p (with Arduino Bootloader)*
  • 28 pin DIP IC Socket
  • 16MHz Crystal Oscillator
  • 2x 22pF and 1x 100nF capacitors
  • 10K resistor
  • USB to Serial adapter**
  • 2x L293D ICs
  • Mini Servo Motor
  • 2x DVD/CD Drives
  • Prototyping PCB Circuit Board Stripboard
  • 4x 2pins Screw Terminal Connector (or 2x 4 pins Screw Terminal Connector)***

*You will also need an Arduino UNO board to program the ATmega328 micro controller.

**USB to Serial adapter will allow the circuit to communicate with the computer through the USB cable, just like Arduino uno does.

***Why to use screw terminal connectors? Because you don't want to solder and desolder cables from stepper motors until you find the correct working combination!

For the mounting base:

  • One piece of plexiglass 20x16 cm (thickness 5mm) (for X axis)
  • Two pieces of plexiglass 14x4 cm (thickness 5mm) (for Y axis)
  • A few nut screws, nuts and shims (~20)
  • A few spacers
  • Four supporting angles (preferably plastic)

Instead of plexiglass you can also use wood, metal or parts from dissasembly cd/dvd drives

Tools:

  • Screwdriver
  • Soldering iron
  • Solder
  • Drill
  • Cutting tool (e.g. Dremel) (Optional for cutting plastic/plexiglass parts)
  • Glue

Step 2: Stepper Motors

First step to start building this cnc machine is to disassemble the dvd/cd drives and take off them the stepper motors. Use the screwdriver to open and take off them the rails (see 1st image above).

Now that we have the two stepper motors we need to solder some cables on them. Proceed with caution, see the 2nd image above. Now we need to find the correct combination to drive and use them correctly, so take a multimeter with alligator clips (3rd image) and put it on "short-circuit" function (4th image). Usually (5th image), the first and second cables are closing the circuit - the led is turned on and a beep sounds - this means that we have found the fist phase-motor of stepper motor. The other two cables, third and forth, uses the second phase-motor of stepper motor.

In my case, one of stepper motors uses the first and third cable for first phase-motor and the second and forth cable for second phase-motor.

Find the correct combination and proceed to next step.

Step 3: Mounting Base, X and Y Axes

Follow the steps below and see the images above:

For X axis:

Place one stepper motor (with rails) on a big plexiglass piece and mark it with a pen in order to open the (4) holes for the screws. Make sure that is perfectly align! (use a triangle ruler). Open the holes and mount the motor with nut screws.

Place on one side of it the four mounting angles and then mark it with a pen in order to open the (8) holes required for the screws. Make sure that the distance between them is 5mm (thickness of plexiglass). The second image above will help you to understand more.

For Y axis:

Place the other stepper motor on two plexiglass pieces and mark them with a pen in order to open the (4) holes for the screws. Again, make sure that the motor is perfectly align (use a triangle ruler).

Place the two pieces of plexiglass on the X axis (big plexiglass piece) and mark them with a pen in order to open the (4) holes required to fit on the mounting angles.

Complete the construction:

Open all holes and complete the construction (see the 3rd and 4th image above). As you can see I placed a metal surface on X axis to fit a note-paper sheet on it. A note-paper sheet usually has dimensions 75mm x 75mm, but remember that printing area is only 40mm x 40mm. Remember, all parts must be perfectly align with others, this is very important!

Step 4: Z Axis

That's the most difficult part of our construction.

You will need something to attach it on Y axis, a flat surface. On that surface you will attach the servo motor (Z axis) and the pen base. Pen (or pencil) must be able to move up and down with the help of servo motor. Watch the above image to understand what you need to do to build Z axis.

Tip: Use your imagination!

Step 5: The Circuit

Now that we have our contraction ready, it's time to build the circuit and test the stepper motors (X and Y axis).

Watch the above image with breadboard circuit schematic.

Steppers motors wiring is something that need patient. On the next step you will find a 'testing' code for x and y axes. If a stepper doesn't work properly you must find the correct working combination by changing the cables between them and the L293D ICs.

Power:

You will need more current than one usb port can give, so you must connect one more usb cable, see the 2nd image above. Connect only power cables (usually red and black) with the primary one. The voltage remains 5V, but you have doubled the current! (from wiki: max. current of USB 2.0: 0.5 A and of USB 3.0 & 3.1: 0.9 A).

Note: If you want to use a different hardware (e.g. motor shield, stepper driver IC) you have to make changes on the above circuit and on the Arduino code. Sorry but I can't help you, search the web to find more info about your hardware. This guide is made for L293D IC motor driver.

Step 6: Testing Stepper Motors - X and Y Axes

Here is the testing code for X and Y axss, embedded using Codebender!

Codebender is an online Arduino IDE - It's the easiest way to program your Arduino board directly from your browser! Just click on the "Run on Arduino" button and that's it! Try it! It's really amazing!

For X axis:

You have to see the X axis motor moves from front to back side (see the image above with black arrow).

For Y axis:

You have to see the Y axis motor moves from left to right side (red arrow).

Step 7: The CNC Code

Here is the main CNC code, embedded using Codebender!

In this part you will see your pen goes up. If don't, change penUp and penDown variables that controlling the servo motor (just click on the "Edit" button).

Press the "Run on Arduino" button to program your Arduino board from your browser!

Step 8: The GCTRL Program

Now we are ready to print our first image! To do this we will use the gctrl.pde processing program. This program sends 'gcode' images to the cnc plotter.

What is gcode? Gcode is a file with X,Y and Z coordinates. Header of this file is set to:

M300 S30.00 (Servo down)

G1 X10.00 Y10.00 F2500.00

G1 X20.00 Y10.00 F2500.00

M300 S50.00 (Servo up)

  • Download the Processing from here, and then download and open the GCTRL.pde application.
  • Click the "play" icon/button to start the program.

------------------------------------------------------------------------------------

Update! You can use gctrl.exe, find files on 'gctrl exe for windows.zip' file.

------------------------------------------------------------------------------------

~Watch the above image~

  • Now press 'p' and select your Arduino serial port.
  • Press 'g' and select the 'TEXT.gcode' or 'gear.gcode' file

(If something goes wrong, press 'x' to stop the plotter and try again)

Step 9: How to Make Your Own Gcode Files

To make gcode files that are compatible with this cnc machine you have to use the Inkscape.

Inkscape is professional quality vector graphics software which runs on Windows, Mac OS X and Linux. It is used by design professionals and hobbyists worldwide, for creating a wide variety of graphics such as illustrations, icons, logos, diagrams, maps and web graphics. Inkscape uses the W3C open standard SVG (Scalable Vector Graphics) as its native format, and is free and open-source 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, if you want you can change font and size. Now click on cursor icon and center the text like the 3rd image above. Select Path from menu and "Object to Path".

How to print images


This is more difficult than texts. Images must have a transparent background. Drag and drop your image in Inkscape. Click ok to the next window. Now you have to re-size the image to fit the 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 gray scale image, and delete the color one behind it. Move the grey image to the correct place again and click from Path menu "Object to path". The 6th image above show how to delete image outline.

Export as gcode file

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

Step 10: Well Done!

You have successfully completed this tutorial and you have your own Arduino mini CNC Plotter!!!

I hope you liked this, let me know in the comments, I would like to see photos of your CNC machines!

Comments

author
HyosikB made it! (author)2016-10-10

Hello.

I changed pen to laser, so it is mini engraver. it's very good.~ ^^ thanks....

I

1476083691607.jpg1476083693155.jpg1476083694558.jpg
author
misterxp (author)HyosikB2017-09-20

Hello HyosikB,

I am very interested in your version. I saw your wood is cut with laser. Is it the same laser as you used here or more powerfull?

Thanks!

author
StephaneL2 (author)HyosikB2016-10-17

How did you connect the laser?

author
HyosikB (author)StephaneL22016-10-20

I use 500mW laser, It is easy to connect to Arduino, but it needs regulator, 3.5 V to 5V or 7.5V.

also you should change the source code, penUp() / penDown() to laserOn(), laserOff().

Then it will be working well. ^^

author

plz ,, give me the code.

author

This version has some bugs..

It use SD card, and you should make 2 kinds of files.

1. config.txt

It has only 1 charactor 1 to 9. it controls delay time to stay. ( i.e it can controls power of laser )

2. draw.bmp

it is image of you want to draw.

it must be 240 by 240 bit map format. ( if it is not 240 by 240, there is some bug. T.T )

after move 2 files, and power on.

Then , you can draw your ouwn image.



#include <SD.h>

#include <Stepper.h>

// CS----------------------------------PIN 4
// SCK (CLOCK)-------------------------PIN 13
// MISO--------------------------------PIN 12
// MOSI--------------------------------PIN 11

#define Laser 1
// step 1 = 2,3,5,6
// step 2 = 7,8,9,10


#define Laser_Speed 200
#define Start -240
#define STEPS 200

const int chipSelect = 4;

Stepper stepperY(STEPS, 2, 3, 5, 6);
Stepper stepperX(STEPS, 7,8, 9, 10);

int delay_time = 500;

File dataFile;
int Image_Height;
int Image_Width;
int Image_Data_Low;
int BitsPerPixel;
char buf[32];

void Image_File_Open();
void File_Close();
void Init_Step();
void Draw1();
void Draw24();
int Power=1;

void setup()
{
Serial.begin(9600);
Serial.println("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
return;
}
Serial.println("card initialized.");

dataFile = SD.open("config.txt", FILE_READ);
if (dataFile) {
int N=0;
Serial.println("config Open OK");
dataFile.read(&N,1); // Power Control 1 to 9
delay_time = N-48; // char to num
Serial.print("Delay time = ");
Serial.println(delay_time);
dataFile.read(buf,3); // depth
Power = atoi(buf);
Serial.print("Resolution = ");
Serial.println(Power);
dataFile.close();
} else {
Serial.println("error opening config, set default");
delay_time = 3;
Power = 1;
}
Image_File_Open();
Init_Step();

if ( BitsPerPixel == 1 )
Draw1();
else if ( BitsPerPixel == 24 )
Draw24();
File_Close();
}

void Image_File_Open()
{
int N;

// see if the card is present and can be initialized:
dataFile = SD.open("draw.bmp", FILE_READ);
if (dataFile) {
Serial.println("Read Open OK");
} else {
Serial.println("error opening draw.bmp");
}


dataFile.read(buf,10); // Dummy
dataFile.read(&N,4); // Image Start point read
int Image_Start = N ;
Serial.print("Image Start=");
Serial.println(Image_Start);
dataFile.read(buf,4); // Dummy
dataFile.read(&N,2); // Image width.
Image_Width = N;
dataFile.read(&N,2); // Image width.
Serial.print("Image Width=");
Serial.println(Image_Width);
dataFile.read(&N,2); // Image Height.
Image_Height = N;
dataFile.read(&N,2); // Image Height.
Serial.print("Image Height=");
Serial.println(Image_Height);
dataFile.read(buf,2); // Image Height.
dataFile.read(&N,2); // Image Height.
BitsPerPixel = N;
Serial.print("BitPerPixel=");
Serial.println(BitsPerPixel);

Image_Data_Low = ((int)((BitsPerPixel*Image_Width+31)/32))*4;
Serial.print("Image_Data_Low=");
Serial.println(Image_Data_Low);
dataFile.seek(Image_Start); // go to Image Start ;
}
void File_Close()
{
dataFile.close();
}

void Init_Step() {
stepperX.setSpeed(Laser_Speed);
stepperY.setSpeed(Laser_Speed);

stepperY.step(Start);
stepperX.step(Start);

Serial.println("Step Motor initialized.");

}

void Draw1()
{
int i,j,k,N;

Serial.println("Draw1 Start");

for(i=0;i<Image_Height;i++) {
for(j=0;j<Image_Data_Low;j++) {
N=0;
dataFile.read(&N,1);
for (k = 7; k >=0 ; k--) {
if (!(N & (1 << k))) {
digitalWrite(Laser,HIGH);
delay(delay_time);
digitalWrite(Laser,LOW);
}
stepperX.step(1);
}
}
stepperY.step(1);
stepperX.step(Start);
}
}
void Draw24()
{
int i,j,k,N,cnt,n1=0,n2=0,n3=0;

Serial.println("Draw24 Start");
for(i=0;i<Image_Height;i++) {
for(j=0;j<Image_Data_Low;j+=3) {
N = 0;
if ( j >= Image_Width*3) {
Serial.print("Image Height = ");
Serial.print(i);
Serial.print(" Image Width = ");
Serial.print(j);
Serial.print(" SKIP = ");
Serial.println(Image_Data_Low-Image_Width*3-1);
dataFile.read(buf,Image_Data_Low-Image_Width*3-1);
break;
}
dataFile.read(&n1,1);
dataFile.read(&n2,1);
dataFile.read(&n3,1);
N = (int)((n1+n2+n3)/3);
N =((int)(N/Power))*Power;
digitalWrite(Laser,HIGH);
delay((int)((256-N)*2/delay_time));
Serial.print("Y=");
Serial.print(i);
Serial.print(" X=");
Serial.print(j);
Serial.print(" D=");
Serial.print((int)((256-N)*2/delay_time));
Serial.print(" N=");
Serial.println(N);
digitalWrite(Laser,LOW);
stepperX.step(1);
}
stepperY.step(1);
stepperX.step(Start);
}
}
void loop()
{
}

author
bonatius (author)HyosikB2016-11-28

Hi,

could you write what kind of laser do you use? Thank you.

author
roccog7 (author)2017-09-19

will someone make me one I will pay you

author
crazyg12 (author)2017-09-01

how to edit this code to use the motor shield

author
ajd21 (author)2017-08-24

Hi!

Thank you for your tutorial, i followed it and X axis and Y axis testing programs are working fine :)

But when I upload a program from a picture/text, the Y axis start runing and got stuck directly on the frame and the motor keep running in this direction...

I don't know where the defect comes from, can you help me?

I am using an arduino nano V3 atmega 168 like from aliexpress

author
ShahjalalB (author)2017-08-22

please systematic laser diode cnc

shaheen814@gmail.com

author
vpsekharan made it! (author)2017-07-31

Thanks for the fantastic project. I have made one. Here is the video of my version. Thank you once again.

VID_20170729_161818.mp4
author
sisodiakaran made it! (author)2016-11-18

Thanks for the awesome tutorial. Here is my version of the machine. I have created a test run video, you can see here:

DSCN0148.JPGDSCN0142.JPGDSCN0118.JPGDSCN0136.JPGDSCN0158.JPGDSCN0122.JPG
author
RAJESH-MrX (author)sisodiakaran2017-07-22

can u give me the code

author
sisodiakaran (author)RAJESH-MrX2017-07-22

Which code you are asking for?

author
naveen9542 (author)sisodiakaran2017-02-04

My cnc is not drawing correctly it draws what ever it wants please help

author
MaxA55 (author)sisodiakaran2017-01-05

did you use arduino nano instead of UNO?

author
sisodiakaran (author)MaxA552017-01-05

Actually I used Arduino Mini...

author
Sdyasin (author)2017-02-05

Hello I made machine ........But after uploading the code it isn't working but the servo motor is giving slight motion.. Please any one help me

IMG_20170204_183448.jpgIMG_20170205_141303.jpg
author
RAJESH-MrX (author)Sdyasin2017-07-22

same in case of me

author
umairahmadh (author)Sdyasin2017-02-05

How you power up the system? Did the stepper motors work in the test part of this instructable?

author
Sdyasin (author)umairahmadh2017-02-06

Hey its ok now and I have a small problem,inkscape isn't saving the gcode at last it is showing some errors please help me.

author
Itihash (author)2017-05-29

Hi,

My servo motor (Z axis) runs but DVD stepper motors (X and Y axis) don't run. what i need to do?

author
itavaci (author)2017-04-14

Hi

Is gctrl compatible with Windows 10, I did run it a couple of times, cannot do any selections, pressing "p" or "g" button does not work. Your help is much appreciated.

author
hyG made it! (author)2017-04-01

Hello everyone!

First, big thank you to an author of this tutorial. I can't believe I completed it, but on the other hand, I am proud of myself. I came across a lot of problems, but every time I solved one, I learned new things. I also learned how do CNC machines work and I got into the robotics. After completing this project I will be probably trying to make a CNC laser cutting machine. My version of the machine, shown in pictures, works pretty nice. I wasn't expecting that, but it is pretty accurate (but less than the author's one, judging by attached video). Some things could be done in better way, but I am still happy with what I have :)

BIG, BIG and once again BIG THANK YOU to the author and sorry for mistakes in language :)

17692958_1038127489656501_88005140_o.jpg17759091_1038127559656494_2009876079_o.jpg
author
nepenth0 (author)2017-03-14

Got the steppers up and running with gcode but the servo for the z-axis doesn't move, only makes different noises when penUp or penDown reads. Any suggestions?

author
Asadh (author)nepenth02017-03-31

power your circuit from external source. USB terminal not provides enough current that may drive 3 motors together.

author
IshanD13 (author)2017-02-16

i have a problem

author
FahimF (author)2017-02-11

Hi,
Can i use an adruino nano instead of adruino uno???

author
PratikG36 (author)2017-02-06

Hi,

Can you please tell me how to connect Bluetooth module hc-06 and the codes also

Thanks.

author
tanvirmahadi (author)2017-01-28

I Don't Where i solder This Item


  • 16MHz Crystal Oscillator
  • 2x 22pF and 1x 100nF capacitors
  • 10K resistor

    Please Give a Clear Circuit Diagram please ....i stack in this point .

    I Purchased all the Component But Don't Understand where to Solder. and the Full Circuit.. someone please help. For Pro Version.
author
umairahmadh (author)tanvirmahadi2017-02-05

Check this. Is this you ask?

ATMega328_standalone.png
author
tanvirmahadi (author)umairahmadh2017-02-06

Exactly I asked for this one ... Do u have the Full Breadboard Diagram of Pro Version ... like Full ...Connection with two L293D ICs Motor driver ..?
I need Complete diagram ...Please Help.

author
umairahmadh (author)tanvirmahadi2017-02-06

I couldn't get one exactly you asked. But this might give you an idea. Compare the ATmega328p's pin outs with arduino uno's pin outs.
Then you got what you want.

Hope this would help. :)

565761458_orig.jpg
author
Abhinav987 made it! (author)2017-01-06

I use old floppy disk cover for bottom part.By doing like this we can plot any where, even on your body.Thanks for the genius brain behind this tutorial

WP_20170106_21_17_52_Pro.jpgWP_20170106_21_18_10_Pro.jpgWP_20170106_21_18_36_Pro.jpg
author
b10101 (author)2016-10-08

Hello All,

Mine moves but stays heavily in one corner, doesn't use the whole 40x40 and prints garbage. I tried to find the Testing stepper motors - X and Y axes as per Step 6 to calibrate as per sketch ie: comments at lines 53 to 55 in the main sketch, but could not find it. Anyone know where the test code is and has anyone had a similar printing issue they have solved.

Cheers

ray

author
HưngĐ8 (author)b101012016-12-05

i got this problem too, have you solved? plz help

author
SubashT1 (author)2016-07-09

Hey hw can i increase the printing area like fOr (A4)

what are the changes i need to make in the coed.......

Please help

Thank you

author
TanzinA1 (author)SubashT12016-11-12

u will need bigger X and Y axes.

author
AdithA1 (author)2016-09-15

I too made it.. but iam having problem. My cnc plotter prints the mirror image of what ever I input to inkscape (text,drawing,images etc)
Can u hlp me to solve this. Plz

author
randobi (author)2016-08-28

This is a good project. I am working through it but I can't seem to make the GCODE P150 work, there is no pause. Can you help?

author
Waheed ullah (author)2016-08-24

please send a circuit diagram o 2d mini CNC ploter.

author
Edward Phantom (author)2016-01-08

On time : the new version of inkscape have a bug with the g-code plugin , always download the version 0.48.5 , or you will not sucessfull export the g-code.



thanks.

author
phyogyi (author)Edward Phantom2016-08-20

Hello after using this old version 0.48.5 , is need to add-on or plug-in extension zip file from this?

https://github.com/martymcguire/inkscape-unicorn.

and please guide to me about how to copy the contents of src/.

Copy the contents of src/ to your Inkscape extensions/ folder.

I don't understand how to copy to under extension folder.

Thank

author
felipehfj made it! (author)2016-07-31

(br) Obrigado pelo tutorial. Eu também fiz a minha. Para a conexão com o computador eu utilizei um modulo bluetooth.

(en) Thanks for the tutorial. I also did mine. For the connection to the computer I used a bluetooth module.

20160731_220721.jpg20160731_220743.jpg20160731_220801.jpg20160731_220823.jpg
author
Ritik KumarS (author)2016-07-01

i've also started making this but using floppy drive motor instead of dc for pen up and down . Struggling while coding with some problems .It would be nice if u help me out to sort these.Here's the code i wrote ..

#include <Stepper.h>

#define LINE_BUFFER_LENGTH 512

// Should be right for DVD steppers, but is not too important here

const int stepsPerRevolution = 20;

// create servo object to control a servo

// 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, 6,7,8,9);

Stepper myStepperZ(stepsPerRevolution, 10,11,12,13);

/* 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 = 30;

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 );

// Decrease if necessary

myStepperX.setSpeed(60);

myStepperY.setSpeed(60);

myStepperZ.setSpeed(50);

// 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 https://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() {

myStepperZ.step(stepsPerRevolution);

Zpos=Zmax;

if (verbose) {

Serial.println("Pen up!");

}

}

// Lowers pen

void penDown() {

myStepperZ.step(-stepsPerRevolution);

Zpos=Zmin;

if (verbose) {

Serial.println("Pen down.");

}

}

author
francisco_noronha (author)2016-06-10

It's done, very good tutorial. Congratulations.

author
tisaconundrum (author)2016-06-04

what version of inkscape are you using? I keep getting errors with the plugin that i'm using.

Traceback (most recent call last):
File "unicorn.py", line 108, in <module>
e.affect()
File "C:\Program Files\Inkscape\share\extensions\inkex.py", line 268, in affect
self.effect()
File "unicorn.py", line 102, in effect
parser.parse()
File "C:\Program Files\Inkscape\share\extensions\unicorn\svg_parser.py", line 230, in parse
self.svgWidth = self.getLength('width', 354) * 0.28222
TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'

This error is telling me that there is never a return of data. Which means that it's on inkscape's side. the NoneType error tells us this.

Thus, i'd like to know what version of inkscape you are using so that i can reduce environment error if this is the case

error.png
author

After doing some research, I've figured out the issue

[Update 04/02/2015: At present, the Unicorn plugin seems not to be compatible with the current Inkscape version. Alternatively, you can either have an older version of Inkscape (with 0.48.5 it still works) install or use another plug-in, such as the Laser Engraver Thanks to Andreas K.)]