Building an XY Plotter

An XY plotter is a machine that can control a plotting instrument (such as a pen or a cutting tool like a blade or a laser) over two axes in a accurate, precise manner. Computer Numerical Control (CNC) machines are very accurate XY plotters than can be used for anything from decorating cakes to cutting steel plates into very precise shapes and sizes.

I wanted to make a drawing robot that would be able to draw the contours of a human face, so I decided to experiment with some very basic stepper motors and a cheap toy plotter that I bought on the Internet. Unfortunately, the plotter itself is so poorly manufactured that it is useless as a drawing tool, but the whole project gave me much insight into the steps needed to design a build a proper computer controlled plotting machine.

The Plotter

Any XY plotter will consist of three main parts

(1) A frame that supports the entire machine

(2) A gantry that moves along (X axis) the frame

(3) A cradle or mounting for the pen that moves across (Y axis) the gantry

Typically the frame will have a single motor mounted on it whose shaft will be attached to the gantry. Depending on how the shaft of this motor is turned, the gantry will run to and fro over the length of the frame. Mounted on the gantry is a second motor that is coupled (in my case by a chain link) to the cradle which holds the plotting instrument. Working together, these two motors can move the cradle along two mutually perpendicular axes and then by placing the pen (which is fixed on the cradle) onto a piece of paper, we can trace out any desired pattern or shape onto the paper.

My cheap XY Plotter

My cheap XY Plotter

Stepper Motors

To drive the cradle along these two axes, we require two motors than are capable of accurate position control so that the amount of movement imparted to the cradle in each axis can be precisely controlled. The easiest way to implement this type of control is by using stepper motors.

A low cost stepper motor with its driver board (ULN 2003A)

A low cost stepper motor with its driver board (ULN 2003A)

A basic stepper motor consists of 4 coils than can be turned on or off by a switching circuit. As each coil is turned on, it generates a magnetic field which attacts a permanent magnet mounted onto the shaft of the motor. This magnet then locks into place when it is exactly opposite the coil that has been energised. To move the shaft away from this position, we de-energise this coil and energise an adjacent coil which in turn turns the shaft towards itself. By doing this in sequence and moving through the coils one by one, we can impart rotary movement to the shaft, exactly 90 degrees at a time. If we then couple the shaft to a gear train, we can define a very precise angle that the final output shaft will rotate by every time we switch the coils on or off. To reverse the direction of rotation, we simply reverse the sequence of energising/ de-energising the coils of the stepper motor. To control speed of the motor, we introduce a time delay between each switching sequence, thereby holding the shaft in one position for a longer time and slowing the motor down.

Its easy to use a microcontroller like an Arduino to control the switching sequence, but to do anything useful we need to be able to drive motors that typically draw a much higher current than the Arduino can handle on its own. To achieve this, we use a chip like the ULN2003 which, put simply is just a bank of 7 darlington transistors, that can switch upto 24V and handle loads of upto 500mA per output pin – perfect for a small stepper motor.

Connections for a ULN2003A

Connections for a ULN2003A

As you can see from the circuit above, to control our stepper motor, we need to use only 4 of of the 7 darlington transistors available on the ULN2003 since our motor has only 4 coils.

To connect the ULN2003 to my Arduino, I bought two ULN chip breakout boards like the one shown below.

Driver Board ULN2003A

Driver Board ULN2003A

As you can see, there are 7 input pins (one for each darlington transistor). A total of five wires exit the board and connect to the stepper motor. Four of these wires are the output lines of the transistors on the ULN chip and one wire is the +12V supply that we will use to drive the stepper motor. There are also 4 red LEDs (one for each output line) that turn ON whenever that particular coil is energised.

Controlling the Motor

To control a stepper motor with this setup, we first designate 4 digital pins on the Arduino that will energise/ de-energise each of the 4 coils in the motor in sequence. Then we switch them on and off is the correct sequence which results in the motor shaft turning at each step. If we know the reduction ratio of the shaft gearing, we can keep on turning the motor until a desired angular movement has been achieved, like this….

void PlotterMotor::StepOnce()
{

if (turnRight) //if we want to turn to the right
{
curStep++;
angleNow++;
}
else //turn to the left
{
curStep--;
angleNow--;
}

if (curStep > 7) curStep = 0; // get back to the first case

if (curStep < 0) curStep = 7; //get back to the last case

switch(curStep)    //switch the coils step by step
{
case 0:

digitalWrite(pinA, LOW);
digitalWrite(pinB, LOW);
digitalWrite(pinC, LOW);
digitalWrite(pinD, HIGH);

break;

case 1:

digitalWrite(pinA, LOW);
digitalWrite(pinB, LOW);
digitalWrite(pinC, HIGH);
digitalWrite(pinD, HIGH);

break;

case 2:

digitalWrite(pinA, LOW);
digitalWrite(pinB, LOW);
digitalWrite(pinC, HIGH);
digitalWrite(pinD, LOW);

break;

case 3:

digitalWrite(pinA, LOW);
digitalWrite(pinB, HIGH);
digitalWrite(pinC, HIGH);
digitalWrite(pinD, LOW);

break;

case 4:

digitalWrite(pinA, LOW);
digitalWrite(pinB, HIGH);
digitalWrite(pinC, LOW);
digitalWrite(pinD, LOW);

break;

case 5:

digitalWrite(pinA, HIGH);
digitalWrite(pinB, HIGH);
digitalWrite(pinC, LOW);
digitalWrite(pinD, LOW);

break;

case 6:

digitalWrite(pinA, HIGH);
digitalWrite(pinB, LOW);
digitalWrite(pinC, LOW);
digitalWrite(pinD, LOW);

break;

case 7:

digitalWrite(pinA, HIGH);
digitalWrite(pinB, LOW);
digitalWrite(pinC, LOW);
digitalWrite(pinD, HIGH);

break;

default:

digitalWrite(pinA, LOW);
digitalWrite(pinB, LOW);
digitalWrite(pinC, LOW);
digitalWrite(pinD, LOW);

break;

}

delayMicroseconds(stepDelay * 1000);//wait a moment to allow the shaft to move

}

Since our XY plotter will have two motors (one for each axis), we need to define a total of eight pins on the Arduino (4 pins for each motor).

One peculiarity of controlling an XY plotter is that we need to ensure that BOTH motors COMPLETE their turn AT THE SAME TIME, and therefore the two motors may have to turn at different speeds.

To illustrate this, suppose we are starting from (0,0) and want to move to (45,45). Clearly, if both motors turn at the same speed, they will both reach (45,45) at the same time. Next, suppose we want to move from (0,0) to (30,90). In this case, if both motors move at the same speed, then when the X motor reaches 30, the Y motor will also be at 30 and then the X motor will remain stopped while the Y motor keeps on turning till it reaches 90. So, to ensure that BOTH motors reach (30, 90) at the SAME time, we need to make the Y motor turn 3 times faster than the X motor. See the picture below…

To reach their final points at the same time, the X and Y motors may need to turn a different speeds

To reach their final points at the same time, the X and Y motors may need to turn a different speeds

To implement this speed control, I wrote the following code that checks to see which motor needs to be speeded up to ensure both motors reach their respective destination values at the exact same time. We also need to factor in the angle that the output shaft turns after each step of the motor. In my case, this was about 0.72 degrees and so I have used a MOTOR_ERROR value = 0.8.

int nStepsX, nStepsY;

if(abs(errX) >= abs(errY)) // X motor has to turn more
{
nStepsX = round(abs(errX/errY));//X will turn more steps
nStepsY = 1;                    //Y will turn only 1 step
}
else    // Y motor has to turn more
{
nStepsY = round(abs(errY/errX));//Y will turn more steps
nStepsX = 1;                    //X will turn only 1 step
}

while (abs(errX) >= MOTOR_ERROR || abs(errY) >= MOTOR_ERROR)
{
//do a stepping sequence

if(abs(errX) >= MOTOR_ERROR)
{
for(int i = 0; i < nStepsX; i++)
{
//step X motor one step

XMotor->StepOnce();
}

}

if(abs(errY) >= MOTOR_ERROR)
{
for(int i = 0; i < nStepsY; i++)
{
//step Y motor one step

YMotor->StepOnce();
}

}

//recalculate the error

curX = XMotor->GetAngle();
curY = YMotor->GetAngle();

errX = x - curX;
errY = y - curY;

} // end of while loop

The complete project is implemented using two stepper motors that are controlled through a plotter_motor class that I wrote in c++.

The source code for the entire project can be downloaded from here, and the video below shows how the stepper motors can be controlled through the serial interface. You can also see that even though the motors work perfectly, poor design and build quality of the plotter I bought (from a toy company called Ikenjoy) results in plenty of shaking of the cradle as it moves, RENDERING IT QUITE USELESS AS A DRAWING TOOL. But nonetheless, the stepper motor code is quite robust and if I ever decide to go in for a better quality frame, I’m quite certain everything else given here will work out-of-the-box.

Advertisements

6 thoughts on “Building an XY Plotter

    • Again, no sorry. I just used this cheap toy kit to do this. But if youre looking to build a proper XY plotter or CNC machine, there are many plans available on the internet, also many kits are available too. Look at 3Dprintersonline.com for a cheap kit. Thats where I bought parts for my 3D printer.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s