Mini Arduino Plotter Without a Servo Motor
Intro: Mini Arduino Plotter Without a Servo Motor
In this project I will show you how to turn two old DVD-drives into a mini plotter.this project is simple and easy to do and makes a good practice if you want to make a real CNC machine(this is why i started this project to prepare my self for a bigger CNC),you get to drive stepper motors and convert vector files to gcode..
this plotter is diffrent from the others because i used the cd tray mechnism for the z axis instead of a servo motor to lower the cost of the project hope you like it
let's get started :
Parts and tools:
2 - DVD-drives
3 - L293 H-bridges IC
1- Arduino uno
1 - Breadboard
- Some wires
- hot glue or something similar
- small pieces of plastic
- USB cable (i power the circuit from the pc)
1 - screw driver
i filmed all the steps on my youtube channel so check them out for more information :
Tunisian Maker : https://www.youtube.com/channel/UCsFmFKMpUdyIiE55W3KsTzw
STEP 1: Gathering the Parts We Need From the DVD-drives
in this step we will begin by disassembling the DVD-drives to get the stepper motors and the carriages of the laser that reads the disk it's simple grab a screwdriver open the metal case and keep it it'll be the main body of our plotter also we will need the plastic mechanism of the DVD tray for our Z-axis this is how it looks :
this video is for step 2 and 3 also :
STEP 2: Wiring the Stepper Motors
This is a tricky part cause the stepper motors are tiny and you need to take your time and be careful not to damage the motor cause i did and this is why:(IMPORTANT)
the stepper motor wires are attached in place with the plastic connector itself so if you remove the old connector the wire get loose and its hard to recover them after so you need to wire the new ones on top of the old one
each stepper motor needs 4 wires cut the four wires to the same length put a tip of solder on top then solder them to the stepper motor.
STEP 3: Assembling the Plotter
the base of our plotter is the metal case itself i attached it with screws and bolts but you can use hot glue.
i mounted the X and Y axis perpendicular to each other with hot glue i didn't measure anything but it worked fine
for the Z axis i glued a piece of plastic to its back and glued it to the carriage of the Y axis
STEP 4: Wiring the Circuit
get your breadboard put the 3 L293 IC first and wire the wires around them the last step would be wiring the motors
the drawings show it all.now before wiring the motors we need to find out the two pairs of coils i used my multimeter to find out the connected wires and connected each pair on a side of the IC
For the z axis it has a built in dc motor wich connects on a side of the third IC.
connect the arduino:
X axis 2,3,4,5
Y axis 6, 7,8,9
Z axis 10 11 but you can change it in the code if you want
this is the video :
STEP 5: Testing the Connections and the Stepper Motors
its a simple arduino sketch using the fuctions of the stepper library like so:
For the X axis
#include <Stepper.h>
const int stepsPerRevolution = 20; //Connection pins: Stepper myStepperX(stepsPerRevolution, 8,9,10,11); void setup() { //Set speed: myStepperX.setSpeed(100); //max 250 steps for dvd/cd stepper motors myStepperX.step(160); delay(100); } void loop() {
}
For the Y axis
#include <Stepper.h>
const int stepsPerRevolution = 20; //Connection pins: Stepper myStepperX(stepsPerRevolution, 6,7,8,9); void setup() { //Set speed: myStepperX.setSpeed(100); //max 250 steps for dvd/cd stepper motors myStepperX.step(160); delay(100); } void loop() {
}
For the Z axis :
void setup() {
// Setup Serial.begin( 9600 ); pinMode(10, OUTPUT); pinMode(11, OUTPUT); delay(200);}
// Raises pen
void penUp() { digitalWrite(I1 , LOW);
digitalWrite(I2 , HIGH);
delay(200);
digitalWrite(I2 , LOW);
digitalWrite(I1 , LOW);
Serial.println("Pen up!"); }
// Lowers pen void penDown() {
digitalWrite(I2 , LOW);
digitalWrite(I1 , HIGH);
delay(200);
digitalWrite(I2 , LOW);
digitalWrite(I1 , LOW);
Serial.println("Pen down."); }
void loop() {
penUp();
penDown();
}
STEP 6: Make G-code and Start Plotting
you need inkscape version 0.48.5 or it wont work and the plugin unicorn gcode plugin and the rest of the software with all the links is included are ready download
53 Comments
rcorycollins 7 years ago
Hi, very nice instructable! I had an idea for a variation on this. Has anyone tried using the geared drive open/close mechanism in an xy plotter like this one? Maybe replace the dc motor that has the small pulley for the belt on it with the stepper motor from the laser slide? Could give you a little bit bigger drawing area. Just a thought.... Thanks!
Sonal More 7 years ago
Sivanand 7 years ago
sir, can u upload the code for testing the circuit..im a bigginner with arduino and stepper...
TunMaker 7 years ago
check step 5 for testing the steppers individualy and the up and down movement
Sivanand 7 years ago
my z axis is not working thats y i askd u...thanks alot :)
Sivanand 7 years ago
sir,i tested it with 2cd drive stepper motors,it works...bt i want to make a cnc machine with dimensions 31x50cm and i had 2- mitsumi m35sp-8nb steppers+1 cd drive motor for z axis..what all changes i have to do in the coding?..
http://www.mitsumi.co.jp/latest/Catalog/pdf/motor_m35sp_8_e.pdf
TunMaker 7 years ago
for x and y i think the circuit can handle it and no code change is needed for z axis you want to replace it with a stepper motor th code you need i already wrote in the comments below =)
Sivanand 7 years ago
sir,it is not working, the stepper is not rotates smoothly...it turns a around20-30degree and stops then takes a next 20-30degree step then stops in an blink of eye...
can u helpme?
TunMaker 7 years ago
for x and y i think the circuit can handle it and no code change is needed for z axis you want to replace it with a stepper motor th code you need i already wrote in the comments below =)
FarazA19 7 years ago
I need help.can i used the Dc motor in place of stepper...!
TunMaker 7 years ago
of course not you need 2 stepper motors and 1 dc motor
shivanshu.gupta 7 years ago
Hey TunMaker, I was wondering if you could do the same thing but having 3 stepper motors. Instead of having a DC Motor on the Z-Axis, you would have another stepper motor. Do you think it would work? and would the Arduino have enough ports to utilize the 3 Stepper motors?
Ritik KumarS 7 years ago
Definitely it works ...i made it using the code Mr.Tunmaker provided
TunMaker 7 years ago
thank you =D
TunMaker 7 years ago
as he told you the code is below in the comments try it and tell me how it works
TunMaker 7 years ago
yes the comments just below were about that the code we used for 3 stepper motors did not test it but it should work the others told me it did here try it nad read the comments below you'll know what am talking about
[code]
/*
Send GCODE to this Sketch using gctrl.pde https://github.com/damellis/gctrl
Convert SVG to GCODE with MakerBot Unicorn plugin for Inkscape available here https://github.com/martymcguire/inkscape-unicorn
More information about the Mini Arduino Plotter at tunisian maker youtube channel
https://www.youtube.com/channel/UCsFmFKMpUdyIiE55W3KsTzw
*/
#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.");
}
}
[/code
shivanshu.gupta 7 years ago
Tyvm I will try this setup out. And report back if it works. :D
Ritik KumarS 7 years ago
Sorry for the trouble .... I did solve the problem .. current was less so motors were not getting proper voltage ...just attached a parallel supply to arduino and noweverything working well andgood .Thanks for your support and help ...I hope i can come up again in future for any other coding or hardware problem.
TunMaker 7 years ago
happy it works mate =) i have a youtube channel https://www.youtube.com/c/tunmaker follow me there and am happy to help anytime =)
Ritik KumarS 7 years ago
it would be nice if u can just text me ur mail so that i can send u the video of it for more clarification