Introduction: CNC Drum Plotter

About: 55+ years in electronics, computers, and teaching ... now retired.

This instructable describes an A4/A3 plotter made from a section of plastic pipe, two BYJ-48 stepper motors and an SG-90 servo. Essentially it is a flat-bed plotter rolled up into a drum.

One motor rotates the drum while the other moves the print-head. The servo is used to raise and lower the pen.

This plotter has a number of advantages over a traditional flatbed plotter:

  • significantly smaller footprint
  • only requires one linear guide rail
  • simple to construct
  • cheap

An on-board interpreter accepts the gcode output from Inkscape.

Communication with the plotter is via a bluetooth link.

The plotter is compatible with the CNC Graphics Tablet described in my instructable

While not a precision instrument the accuracy of this plotter is satisfactory for its intended purpose of transferring watercolor outlines on to paper.

Step 1: The Circuit

The circuit comprises an Arduino UNO R3 microcontroller and a custom shield on which the discrete components are mounted. Power is applied via an external 5 volt 1 amp regulator. The average current is around 500mA.

The BYJ-48 stepping motors are attached to PORTB (pins D8,D9,D10, D11) and PORTC (pins A0,A1,A2,A3). The SG-90 pen-lift servo is attached to pin D3.

The 560 ohm resistors, which may be omitted, provide a measure of short-circuit protection to the arduino should something go wrong. They also make it easier to wire the shield as they act as "jumpers" across the supply rails.

The 1k2 and 2K2 resistors prevent damage to the HC-06 bluetooth module [1] by dropping the 5 volt output from the arduino down to the 3.3 volts.

[1] Unplug the HC-06 bluetooth module when uploading code to the arduino via the USB port. This will avoid any serial port conflicts.

Step 2: The Linear Drive

The linear drive is made from a length of 3mm x 32mm aluminium bar, a strip of aluminium sheet, and four small ball-bearing pulleys.

The aluminum is available from most hardware stores. The U624ZZ 4x13x7mm U-groove pulleys are available from

Simple hand tools are all that you require. Cut the aluminium bar to suit your plotter dimensions.

The motor assembly

Mount the BJY-48 stepping motor through the bar at one end and attach a GT2 20 tooth, 5mm bore, pulley to the motor shaft. Now mount another GT2 pulley at the other end of your bar such that the pulley is able to rotate freely. I used a 5mm diameter tubular (radio) spacer and a 3mm bolt to achieve this.

Now loop a length of GT2 timing belt around the pulleys. Join the timing belt ends by means of a half-twist such that the teeth interleave and fix with a cable tie.

Finally attach the carriage assembly to the timing belt with a cable tie.

The carriage assemby

The carriage assembly is made from a strip of aluminium sheet [1] on to which the U624ZZ pulleys are bolted. If necessary use a 4mm washer to space the pulleys from the aluminium sheet.

The pulleys, which have a 4mm groove, straddle the aluminium bar top and bottom such that there is no vertical movement yet the aluminium strip moves freely left and right.

To ensure that the carriage runs freely, mount the top two pulleys first then, with the pulleys sitting on the bar, mark the positions of the bottom two pulleys. The holes for these two pulleys may now be drilled. Use a small "pilot" drill first to prevent the larger 4mm drill from drifting.

Prior to bending the alumium strip into a "U", drill a hole top and bottom to suit your pen diameter. Now complete the bends.

Attach the timing-belt to the carriage assembly by means of a cable tie and 3mm bolt between the top two pulleys.

The pen-lift assembly

Attach an SG-90 servo to the top of the carriage assembly using one or two cable ties.

Drop your pen down the two holes you have drilled. Ensure that the pen slides up and down freely.

Fasten a "collar" to your pen such that the pen is just clear of the drum when the servo is in the pen-up position.

[1] Aluminium may be cut by scoring both sides of the sheet with a sharp knife (box-cutter) then flexing the cut over the edge of a table. A few wiggles and the the sheet will fracture leaving a straight break. Unlike tin-snips this method doesn't kink the aluminium.

Step 3: The Drum

The drum comprises a section of plastic pipe with two wooden end-plugs [1].

Use a compass, set to the inside radius of your pipe, to draw the end-plug outlines. Now cut around each outline using a fine blade saw ("coping", "fret") then custom fit each end-plug with the aid of a wood rasp. Fasten the end plugs using small counter-sunk wood screws.

A 6 mm engineering bolt through the center of each end-plug forms the axle.

Drum Dimensions

The drum dimensions are determined by your paper size. A drum diameter of 100mm supports A4 portrait and A3 landscape. A drum diameter of 80 mm will only support A4 landscape. Use as small a drum diameter as possible to reduce the inertia ... the BYJ-48 motors are only small.

A drum diameter of 90mm is ideal for A4 portrait and A3 landscape paper as the opposite edges, when wrapped around the drum, overlap by approximately 10mm which means that you only have one seam to tape into place.

Rotating the drum

Each axle passes through an aluminium end bracket such that the drum is able to rotate freely. End float is prevented by means of a GT-2, 20 tooth, 6mm bore, pulley fastened to the axle at one end. A continuous GT-2 timing belt links the BJY-48 geared stepping motor to the drum. The motor requires a pulley with a bore size of 5mm.

[1] Plastic end-plugs are available for most pipe diameters but were rejected as they fit over the pipe rather than inside and the plastic tends to flex. They would probably be okay if a continuous axle was used instead of the bolts ... but then you require some method of fixing the axle to the end-plugs.

Step 4: Construction Tips

Ensure that the pen travels along the center of the drum. This may be achieved by cutting the corners out of the wooden supports. If the pen is off-center it will tend to slide down the side of the drum.

Accurate drilling of the two pen holes is important. Any wobble in the pen guide or carriage assembly will cause wobbles along the X-axis.

Don't over-tighten the GT-2 timing belts ... they just need to be taut. BYJ-48 stepping motors don't have a lot of torque.

BJY-48 stepping motors often exhibit small amounts of backlash which is insignificant along the X-axis but is of concern when it comes to the Y-axis. The reason for this is that one rotation of the Y-axis motor equates to one rotation of the drum, whereas the pen-carriage requires many turns of the X-axis motor to traverse the length of the drum. Any Y-axis backlash can be eliminated by keeping a constant torque on the drum. A simple method is to attach a small weight to a nylon cord wrapped around the drum.

Step 5: Bresenham's Line Drawing Algorithm

This plotter uses an optimised version [1] of Bresenham's line drawing algorithm. Unfortunately this algorithm is only valid for line slopes less than or equal to 45 degrees (i.e one octant of a circle).

To get around this limitation I "map" all XY inputs to the first "octant", then "unmap" them when it's time to plot. The input and output mapping functions to achieve this are shown in the above diagram.


The remainder of this step may be omitted if you are familiar with Bresenham's algorithm.

Let us draw a line from (0,0) to (x1,y1) where:

  • x1=8=horizontal distance
  • y1=6=vertical distance

The equation for a straight line passing through the origin (0,0) is given by the equation y=m*x where:

  • m=y1/x1=6/8=0.75=slope

Simple Algorithm

A simple algorithm for plotting this line is:

  • int x1=8;
  • int y1=6;
  • float m=y1/x1;
  • plot(0,0);
  • for (int x=1; x<=x1; x++) {
  • int y=round(m*x);
  • plot(x,y);
  • }
Table 1: Simple Algorithm
00.750 0
10.750.75 1
20.751.5 2
30.752.25 2

There are two problems with this simple algorithm:

  • the main loop contains a multiplication which is slow
  • it uses floating point numbers which is also slow

A graph of y versus x for this line is shown above.

Bresenham's Algorithm

Bresenham introduced the concept of an error term 'e' which is initialised to zero. He realised that the m*x values shown in table 1 can be obtained by successive addition of 'm' to 'e'. He further realised that y is only incremented if the fractional part of m*x is greater than 0.5. To keep his comparison within the range 0<=0.5<=1 he substracts 1 from 'e' whenever y is incremented.

  • int x1=8;
  • int y1=6;
  • float m=y1/x1;
  • int y=0;
  • float e=0;
  • plot(0,0);
  • for ( int x=1; x<=x1; x++) {
  • e+= m;
  • if (e>= 0.5) {
  • e -= 1;
  • y++;
  • }
  • plot(x,y);
  • }
Table 2: Bresenham's Algorithm

If you examine the algorithm and table 2 you will observe that;

  • the main loop only uses addition and subtraction ... there is no multiplication
  • the pattern for y is the same as for table 1.

But we are still using floating point numbers ... let's fix this.

Bresenham's (Optimized) Algorithm

Bresenham's floating point algorithm can be converted to an integer form if we scale 'm' and 'e' by 2*x1 in which case m=(y1/x1)*2*x1=2*y1

Apart from scaling 'm' and 'e' the algorithm is similar to that above except:

  • we add 2*y1 to 'e' each time we increment 'x"
  • we increment y if e is equal or greater than x1.
  • we subtract 2*x1 from 'e' instead of 1
  • x1 is used for the comparison instead of 0.5

The speed of the algorithm can be further increased if the loop uses zero for the test. To do this we need to add an offset to the error term 'e'.

  • int x1=8;
  • int y1=6;
  • int m=(y1<<1); //constant: slope scaled by 2*x1
  • int E=(x1<<1); //constant: 2*x1 for use in loop
  • int e = -x1; //offset of -E/2: test now done at zero
  • plot(0,0);
  • int y=0;
  • for (x=1; x<=x1; x++) {
  • e += m;
  • if (e>=x1) {
  • e -= E
  • y++;
  • }
  • plot(x,y);
  • }
Table 3: Bresenham's (Optimized) Algorithm
xmEee - Ey

Once again the pattern for y is the same as in the other tables. It is interesting to note that table 3 only contains integers and that the ratio of m/E=12/16=0.75 which is the slope 'm' of the line.

This algorithm is extremely fast as the main loop only involves addition, subtraction, and a comparison with zero. Multiplication is not used apart from when we initialize the values for 'E' and 'm' using a "left-shift" to double the values of x1 and y1.

[1] This optimised version of Bresenham's algorithm is from a paper "Bresenham Line and Circle Drawing", copyright © 1994-2006, W Randolph Franklin (WRF). His material may be used for non-profit research and education, provided that you credit him, and link back to his home page,

Step 6: The Code

Download the attached file into a folder of the same name then upload it to the plotter using your arduino IDE (integrated development environment).

Unplug the HC-06 bluetoorh module before attempting the upload. This is necessary to avoid a serial port conflict with the USB cable.

Third Party Code

In addition to the above .ino code you will need the following software packages which are free / donation-ware:

Instructions for installing and using each of the above third party packages may be found in my article

Step 7: Menu

Make a bluetooth connection with your plotter using "Teraterm".

Switch your "caps lock" on as all commands are in upper case.

Type the letter 'M' and a menu should appear as shown above.

The menu is reasonably self explanatory:

  • M (or M0) brings up the menu
  • G0 allows you to send the pen to a specific XY co-ordinate with the pen raised.
  • G1 allows you to send the pen to a specific XY co-ordinate with the pen lowered.
  • T1 allows you to position your pen over your 0,0 co-ordinate. Type 'E' to exit.
  • T2 allows you to scale your drawiing. For example "T2 S2.5" will scale your drawing 250%. The default scale is 100%
  • T3 and T4 allow you to raise or lower the pen.
  • T5 draws an "ABC" test pattern.
  • T6 draws a "target".
  • T7 draws a set of radial lines, the purpose of which is to verify that Bresenham's algorithm is working in each of the eight "octants"


  • all pen moves use the drawing scale set using menu option T2
  • the "17:" and "19:" numbers are the "Xon" and "Xoff" terminal handshake codes from the arduino interpreter.

Step 8: Calibration

The values for X_STEPS_PER_MM and Y_STEPS_PER_MM are for a 90mm diameter drum.

Values for other drum diameters can be calculated using the following relationships:

  • the circumference of the drum is PI*diameter
  • 2048 steps equals one revolution of each motor shaft
  • one revolution of a GT-2 pulley equates to 40 millimeters linear movement of a timing belt

Another method is to enter the following commands,

  • G1 X0 Y100
  • G1 X100 Y100

then measure the length of the resulting lines and "scale" the values for X-STEPS_PER_MM and Y_STEPS_PER_MM

Step 9: Gcode Preprocessing

This plotter only requires four of the Inkscape gcodes (viz: G0, G1, G2, G3). The code will execute significantly faster if we remove all unnecessary gcodes and comments.

In order to do this you need a copy of "Notepad++". This free text editor contains a "regular expression" search engine for finding and removing unwanted text. Notepad++ is available from

Open the file to be modified with Notepad++ and position your cursor at the top of the file.

Select "View/Show Symbol/All Characters" followed by "Search/Replace..." from the top menu bar.

Click the "Regular Expression" check box (see 1st image) and enter each of the following code sequences into the search box.

Click "Replace All" after each entry:

  • %
  • \(.*\)
  • ^M.*$
  • Z.*$

The above regular expressions remove all % symbols, all comments shown in brackets, all M codes, all Z codes and the codes which follow.

Now click the "Extended Expression" checkbox (see 2nd image) and enter the following code sequence:

  • \r\n\r\n\r\n

This expression removes the unwanted carriage-returns and line-feeds created by the first sequence.

Save your file under a different name using "Save As".


Step 10: Results

This plotter was built as "proof of concept" and never intended to be perfect. Having said that the results are not too bad. They definitely meet my design goal of transferring watercolor outlines onto paper.

The first three images are the built-in test patterns T5,T6,T7 respectively.

The "Hello World !" pattern was sent to the plotter via bluetooth. A "pre-processed" copy of this file is attached.

Step 11: Code Update

The code for this plotter has been updated to Drum_Plotter_V2.ino.

Changes from the original Drum_Plotter.ino include:

  • smoother pen positioning
  • now recognises G02 gcode instructions (clockwise arcs)
  • now recognises G03 gcode instructions (counter-clockwise arcs)

The attached diagram outlines my method for calculating the arc angle.

Step 12: Drum_plotter_v3.ino

A code update for "CNC Drum Plotter" is attached.

"drum_plotter_v3.ino" fixes a minor bug that affected the plotter accuracy.

Change history

Version 2:

  • Bi-arc curves added

Version 3:

The following functions were rewritten to address a minor bug that affected the plotter accuracy.

  • (int) replaced with round() in the move_to() function.
  • draw_line() function "octant" search algorithm improved
  • The interpreter now uses string functions rather than pointers which simplifies the design. For example we can now search for "MENU" rather than look for the letter 'M' then extract the integer number that follows. This allows you to personalize the plotter with your own commands.

Step 13: Drum_plotter_plotter_v4.ino

16 January 2017:

The code for this drum plotter has been further optimised. Additional features have been added.

The changes include:

  • faster draw_line() algorithm
  • matching move_to() function
  • step counters
  • minor bug fix

For further details read the comments within "drum_plotter_v4.ino" attached.

  Click here   to view my other instructables.