Search Results for: 7475a

HP 7475A Plotter: Rebuilt Carousel Drive

A followup to the saga of the HP 7475A plotter with a broken carousel drive:

With the information you shared, we were able to successfully model and reconstruct the drive wheel in only a couple of days.

One useful thing we discovered is there’s a lot of room for error – so long as the pin catches and the wheel isn’t slipping on the motor shaft, the mechanism will work. The grooves and the interior radius of the original part aren’t critical.

Because of your heads up about Geneva wheels, I found this excellent website – – which includes a link to a Geneva wheel calculator. With the measurements you sent and a measurement off of the pen carousel, the calculator generated near perfect dimensions for a replacement. There was a little sanding and rounding to fit but it was certainly within tolerance.

Interestingly, the pieces of the drive wheel that I pulled out of the case revealed a small hidden detail. On the underside, there’s a collar around the motor shaft that gives the cam an extra ~.03″ thickness. Presumably this is to help reduce friction during travel. Our prototype doesn’t take this detail into consideration – we’ve had no issues with friction, and we compensated for the thickness by making the pin a little longer – but it’s meaningful to note.

HP7475A Carousel Drive - cam1

HP7475A Carousel Drive – cam1

The broken pieces also confirmed the thicknesses and radii of the original part, and so my partner was able to build an accurate technical drawing of the drive wheel for future fabrication.

While we intend to make a better replacement, our prototype was built with dense 1/8″ mat board, PVA glue, binder clips, and a short piece of wooden dowel from our bits box. Basically just stuff we had kicking around the studio. It’s held up shockingly well. A little dented around the edges from hitting the carousel, but there’s no slippage. I’m thinking I’ll use it until it falls apart, just to see how long it takes.

HP7475A Carousel Drive - repaired - cam2

HP7475A Carousel Drive – repaired – cam2

Attached, find a technical drawing comparing the original drawing to our prototype (measured in good old fashioned 1980s inches); a photo of the retrieved piece, showing the collar on the reverse side; and a photo of the prototype in place. Feel free to share these – everyone deserves a working plotter!

7475a drive wheel

7475a drive wheel

Once the carousel was working, my roommate – an electrical engineer – hooked me up with a custom serial cable, a Raspberry Pi, and a crash course in Python, so now that I can communicate with the plotter, the possibilities are staggering. I’m thrilled to add this machine to my print studio arsenal!

I love a happy ending …

For anyone with a new-to-you plotter, search the blog for 74754A to find info on replacing failed electrolytic capacitors, adapting Sakura Micron pens, refilling old plotter pens, building a serial cable, hacking Chiplotle to actually use hardware handshaking, and plotting Superformulas. Let me know how you got your plotter working!



1 Comment

HP 7475A Plotter: Pen Carousel Geneva Drive

A note arrived from someone who obviously couldn’t pass up an orphaned HP 7475A plotter:

The plotter I received works beautifully, except that the carousel doesn’t rotate. I found a YouTube video showing a 7475a running with the cover off, and there’s a little plastic piece – it looks like a teardrop – that advances the carousel, and is apparently part of the carousel motor assembly. Mine is missing that piece …

The keyword is Geneva drive, a wonderfully simple technique to convert one rotation of the stepper motor into 1/6 turn of the pen carousel, with no need for fancy sensors.

The (unofficial) HP Computer Museum has All The HP 7475A Documents and the Plotter Service Manual shows All The Parts. And, of course, I’ve written a bit about my adventures with an old 7475A.

Back in the day, you could get the entire Pen Carousel Housing Assembly w/ Motor (PN 07475-60175) as a unit and the Carousel Motor Only (PN 3140-0687) as a separate thing, but not the Geneva drive wheel:

HP7475A Carousel - Geneva drive cam

HP7475A Carousel – Geneva drive cam

The cam’s drive wheel end (in inches, because early 1980s):

  • 0.25 thick overall
  • 0.10 thick plate under pin end
  • 1.09 OD – rounded end

The pin sticking up from the cam:

  • 0.154 OD (or fit to slot?)
  • 0.16 tall (above base plate)

I have no good (i.e., easy + accurate) way to measure the distance from the motor shaft to the pin, but I doubt it’s critical. As long as the pin doesn’t quite whack the hub end of the slot, it’s all good:

HP7475A Carousel - cam driving

HP7475A Carousel – cam driving

The 0.10 plate + 0.16 pin height don’t quite add up to the 0.25 overall measurement, but that’s certainly measurement error. I’d round the pin length downward and carve the drive from a 1/4 inch sheet.

A 3D printed part would probably work, apart from the accuracy required to fit the D-shaped motor shaft. Perhaps a round hole, reamed to fit the shaft, carefully aligned / positioned, with epoxy filling the D-shaped void, would suffice. A dent in the round hole would give the epoxy something to grab.

I’d be sorely tempted to use an actual metal / plastic rod for the pin, rather than depend on a stack of semi-fused plastic disks. The pin must withstand hitting the end of the “missing” slot during the power-on indexing rotation, because turning the carousel isn’t quite a non-contact sport. Normally, though, it enters the end of the slot without much fuss:

HP7475A Carousel - cam engaging

HP7475A Carousel – cam engaging

The blocked slot sits at the bottom of that picture, with a small locating pin sticking upward just above the circular feature at the end of the arm: we’re seeing the negative of a plug inserted into the original injection mold.

With a bit of luck, another HP 7475A plotter will fascinate everybody within hearing distance!

[Update: It lives! ]



HP 7475A Plotter: 09872-60066 Digitizing Sight

I found this antique on eBay for (somewhat) under HP’s 1980-era $35 price:

HP 09872-60066 Digitizing Sight - overview

HP 09872-60066 Digitizing Sight – overview

The prevailing price for HP 09872-60066 Digitizing Sights seems to be $100 and upwards, with outliers in both directions, so I just couldn’t pass it up.

Anyhow, the fiber optic pipe still works just like it did, back in the day:

HP 09872-60066 Digitizing Sight - text target

HP 09872-60066 Digitizing Sight – text target

The small dot in the middle is actually a paint-filled indentation on the bottom surface:

HP 09872-60066 Digitizing Sight - bottom detail

HP 09872-60066 Digitizing Sight – bottom detail

With the bottom flat on the target, the relayed image is in perfect focus:

HP 09872-60066 Digitizing Sight - top detail

HP 09872-60066 Digitizing Sight – top detail

The bezel recesses the top surface by 25 mil to protect the imaging plane.

OK, it’s a gadget gloat; I have absolutely no intention of ever chucking a piece of paper in the plotter and digitizing any points.


HP 7475A Plotter: Coordinate Pruning

The original SuperFormula equation produces points in polar coordinates, which the Chiplotle library converts to the rectilinear format more useful with Cartesian plotters. I’ve been feeding the equation with 10001 angular values (10 passes around the paper, with 1000 points per pass, plus one more point to close the pattern), which means the angle changes by 3600°/10000 = 0.36° per point. Depending on the formula’s randomly chosen parameters, each successive point can move the plotter pen by almost nothing to several inches.

On the “almost nothing” end of the scale, the plotter slows to a crawl while the serial interface struggles to feed the commands. Given that you can’t see the result, why send the commands?

Computing point-to-point distances goes more easily in rectilinear coordinates, so I un-tweaked my polar-modified superformula function to return the points in rectangular coordinates. I’d originally thought a progressive scaling factor would be interesting, but it never happened.

The coordinate pruning occurs in the supershape function, which now contains a loop to scan through the incoming list of points from the  superformula function and add a point to the output path only when it differs by enough from the most recently output point:

    path = []
    path.append(Coordinate(width * points[0][0], height * points[0][1]))
    outi = 0
    xp, yp = points[outi][0], points[outi][1]
    for i in range(len(points))[1:]:
        x,y = width * points[i][0], height * points[i][1]
        dist = sqrt(pow(x - xp,2) + pow(y - yp,2))
        if dist > 60 :
          path.append(Coordinate(x, y))
          outi = i
          xp, yp = x, y

    path.append(Coordinate(width * points[-1][0], height * points[-1][1]))
    print "Pruned",len(points),"to",len(path),"points"

The first and last points always go into the output list; the latter might be duplicated, but that doesn’t matter.

Note that you can’t prune the list by comparing successive points, because then you’d jump directly from the start of a series of small motions to their end. The idea is to step through the small motions in larger units that, with a bit of luck, won’t be too ugly.

The width and height values scale the XY coordinates to fill either A or B paper sheets, with units of “Plotter Units” = 40.2 PU/mm = 1021 PU/inch. You can scale those in various ways to fit various output sizes within the sheets, but I use the defaults that fill the entire sheets with a reasonable margin. As a result, the magic number 60 specifies 60 Plotter Units; obviously, it should have a suitable name.

Pruning to 40 PU = 1.0 mm (clicky for more dots, festooned with over-compressed JPEG artifacts):

Plot pruned to 40 PU

Plot pruned to 40 PU

Pruning to 60 PU = 1.5 mm:

Plot pruned to 60 PU

Plot pruned to 60 PU

Pruning to 80 PU = 2.0 mm:

Plot pruned to 80 PU

Plot pruned to 80 PU

Pruning to 120 PU = 3.0 mm:

Plot pruned to 120 PU

Plot pruned to 120 PU

All four of those plots have the same pens in the same order, although I refilled a few of them in flight.

By and large, up through 80 PU there’s not much visual difference, although you can definitely see the 3 mm increments at 120 PU. However, the plotting time drops from just under an hour for each un-pruned plot to maybe 15 minutes with 120 PU pruning, with 60 PU producing very good results at half an hour.

Comparing the length of the input point lists to the pruned output path lists, including some pruning values not shown above:

Prune 20
1 - m: 5.3, n1: 0.15, n2=n3: 0.80
Pruned 10001 to 4856 points
2 - m: 5.3, n1: 0.23, n2=n3: 0.75
Pruned 10001 to 5545 points
3 - m: 5.3, n1: 1.15, n2=n3: 0.44
Pruned 10001 to 6218 points
4 - m: 5.3, n1: 0.41, n2=n3: 1.50
Pruned 10001 to 7669 points
5 - m: 5.3, n1: 0.29, n2=n3: 0.95
Pruned 10001 to 6636 points
6 - m: 5.3, n1: 0.95, n2=n3: 0.16
Pruned 10001 to 5076 points

Prune 40
1 - m: 3.1, n1: 0.23, n2=n3: 0.26
Pruned 10001 to 2125 points
2 - m: 3.1, n1: 1.05, n2=n3: 0.44
Pruned 10001 to 5725 points
3 - m: 3.1, n1: 0.25, n2=n3: 0.32
Pruned 10001 to 2678 points
4 - m: 3.1, n1: 0.43, n2=n3: 0.34
Pruned 10001 to 4040 points
5 - m: 3.1, n1: 0.80, n2=n3: 0.40
Pruned 10001 to 5380 points
6 - m: 3.1, n1: 0.55, n2=n3: 0.56
Pruned 10001 to 5424 points

Prune 60
1 - m: 1.1, n1: 0.45, n2=n3: 0.40
Pruned 10001 to 2663 points
2 - m: 1.1, n1: 0.41, n2=n3: 0.14
Pruned 10001 to 1706 points
3 - m: 1.1, n1: 1.20, n2=n3: 0.75
Pruned 10001 to 4446 points
4 - m: 1.1, n1: 0.33, n2=n3: 0.80
Pruned 10001 to 3036 points
5 - m: 1.1, n1: 0.90, n2=n3: 1.40
Pruned 10001 to 4723 points
6 - m: 1.1, n1: 0.61, n2=n3: 0.65
Pruned 10001 to 3601 points

Prune 80
1 - m: 3.7, n1: 0.95, n2=n3: 0.58
Pruned 10001 to 3688 points
2 - m: 3.7, n1: 0.49, n2=n3: 0.22
Pruned 10001 to 2258 points
3 - m: 3.7, n1: 0.57, n2=n3: 0.90
Pruned 10001 to 3823 points
4 - m: 3.7, n1: 0.25, n2=n3: 0.40
Pruned 10001 to 2161 points
5 - m: 3.7, n1: 0.47, n2=n3: 0.30
Pruned 10001 to 2532 points
6 - m: 3.7, n1: 0.45, n2=n3: 0.14
Pruned 10001 to 1782 points

Prune 120
1 - m: 1.9, n1: 0.33, n2=n3: 0.48
Pruned 10001 to 1561 points
2 - m: 1.9, n1: 0.51, n2=n3: 0.18
Pruned 10001 to 1328 points
3 - m: 1.9, n1: 1.80, n2=n3: 0.16
Pruned 10001 to 2328 points
4 - m: 1.9, n1: 0.21, n2=n3: 1.10
Pruned 10001 to 1981 points
5 - m: 1.9, n1: 0.63, n2=n3: 0.24
Pruned 10001 to 1664 points
6 - m: 1.9, n1: 0.45, n2=n3: 0.22
Pruned 10001 to 1290 points

Eyeballometrically, 60 PU pruning halves the number of plotted points, so the average data rate jumps from 9600 b/s to 19.2 kb/s. Zowie!

Most of the pruning occurs near the middle of the patterns, where the pen slows to a crawl. Out near the spiky rim, where the points are few & far between, there’s no pruning at all. Obviously, quantizing a generic plot to 1.5 mm would produce terrible results; in this situation, the SuperFormula produces smooth curves (apart from those spikes) that look just fine.

The Python source code as a GitHub Gist:


HP 7475A: Superformula Successes

In the course of running off some Superformula plots, I found what must be my original stash of B-size plotter paper. Although it wasn’t archival paper and has yellowed a bit with age, it’s the smoothest and creamiest paper I’ve touched in quite some time: far nicer than the cheap stuff I picked up while reconditioning the HP 7475A plotter & its assorted pens.

Once in a while, all my errors and omissions cancel out enough to produce interesting results on that historic paper, hereby documented for future reference…

A triangle starburst:

Superformula - triangle burst

Superformula – triangle burst

Superformula - triangle burst - detail

Superformula – triangle burst – detail

A symmetric starburst:

Superformula - starburst

Superformula – starburst

Superformula - starburst - detail

Superformula – starburst – detail

Complex meshed ovals:

Superformula - meshed ovals

Superformula – meshed ovals

Superformula - meshed ovals - details

Superformula – meshed ovals – details

They look better in person, of course. Although inkjet printers produce more accurate results in less time, those old pen plots definitely look better in some sense.

The demo program lets you jam a fixed set of parameters into the plot, so (at least in principle) one could reproduce a plot from the parameters in the lower right corner. Here you go:

The triangle starburst:

Superformula - triangle burst - parameters

Superformula – triangle burst – parameters

The symmetric starburst:

Superformula - starburst - parameters

Superformula – starburst – parameters

The meshed ovals:

Superformula - meshed ovals - parameters

Superformula – meshed ovals – parameters

The current Python / Chiplotle source code as a GitHub gist:

1 Comment

Lenovo Q150: Setup for HP 7475A Plotter Demo

Starting with a blank 120 GB SSD, I had to disable the “Plug-n-Play OS” BIOS option to get the Lenovo Q150 to boot from a System Rescue CD USB stick. While the hood was up, I told the BIOS to ignore keyboard errors so it can boot headless.


  • 50 GB ext4 partition for Mint
  • 8 GB swap
  • The remainder unallocated

Booting & installing Mint Linux 17.2 XFCE from another USB stick went smoothly, after which it inhaled the usual gazillion updates. Rather than wait for the auto-updater to wake up and smell the repositories, I generally get it done thusly:

sudo apt-get update
sudo apt-get upgrade
apt-get dist-upgrade
apt-get autoremove

Add my user to the dialout group, so I have access to the USB serial converter on /dev/ttyUSB0 that will drive the plotter.

Configure a static IP address that appears in the appropriate /etc/hosts files.

Install some useful packages:

  • nfs-common
  • openssh-server
  • htop and iotop

Set up ssh for public key authentication, rather than passwords, on an unusual port, so everything else can happen from the Comfy Chair upstairs.

Install packages that Chiplotle will need:

  • build-essential
  • python-setuptools
  • python-dev
  • python-numpy
  • python-serial
  • hp2xx

I think some of those would be auto-installed as dependencies by the next step, but now I can remember what they are for the next time around this action loop:

sudo easy_install -U chiplotle
... blank line to show underscore above ...

Plug the old hard drive into a USB-SATA adapter to copy:

Then chuck up some paper and pens to let it grind out art:

HP 7475A - demo plot

HP 7475A – demo plot

It’s good clean fun…

1 Comment

HP 7475A Plotter: One-Button Demo Madness

Back in the day, you could install a Genuine HP 09872-60066 Digitizing Sight in your Genuine HP 7475A plotter, maneuver the sight to an interesting point on the paper, press the Enter button, send the point’s coordinates through the serial port to the computer, then do whatever you like with the numbers.

Here in the future, I twiddled the demo code that draws Superformula patterns to send a digitization command and await the response at the end of each plot. I can then change the paper, press the Enter button, and get the next plot: exactly what I need for the upcoming Poughkeepsie Mini Maker Faire.

The only gotcha turns out to be that, having hacked the Chiplotle interface to use hardware handshaking, there’s no way to tell when the outgoing buffer has drained. Until that happens, the plotter can’t respond to the digitizing command and, eventually, Chiplotle kvetches about not hearing anything.

The least awful solution seems to be sleeping for 40 seconds (!) while the plotter trudges through the last line of the legend (!!), then continuing apace:

        print "Waiting for plotter... ignore timeout errors!"
        while NoneType is type(plt.status):

        print "Load more paper, then ..."
        print "  ... Press ENTER on the plotter to continue"
        plotstatus = plt.status
        while (NoneType is type(plotstatus)) or (0 == int(plotstatus) & 0x04):
            plotstatus = plt.status
        print "Digitized: " + str(plt.digitized_point)

When the interface times out, Chiplotle doesn’t set the status code to anything in particular (which makes sense), so you can’t do anything useful with it. Therefore, the operand order in the last while statement matters: you can’t convert a value of type NoneType into anything else.

The other change wraps the entire plotting loop with an always-and-forever loop: hit Ctrl-C to break out at the end of the day.

You can’t change the new plot’s paper size, because the digitizing command preempts the Enter button that’s part of the Enter+Size combination. That makes perfect sense, even in retrospect.

Testing that gave me the opportunity to run all the pens, refilled and OEM, through their paces:

HP 7475A - Superformula demo

HP 7475A – Superformula demo

The Sakura pens in their adapters continue to work well:

HP 7475A - Superformula - Sakura pens

HP 7475A – Superformula – Sakura pens

They’re such unique snowflakes…

The complete Python source code:

from chiplotle import *
from math import *
from datetime import *
from time import *
from types import *
import random

def superformula_polar(a, b, m, n1, n2, n3, phi):
    ''' Computes the position of the point on a
    superformula curve.
    Superformula has first been proposed by Johan Gielis
    and is a generalization of superellipse.
    Tweaked to return polar coordinates

    t1 = cos(m * phi / 4.0) / a
    t1 = abs(t1)
    t1 = pow(t1, n2)

    t2 = sin(m * phi / 4.0) / b
    t2 = abs(t2)
    t2 = pow(t2, n3)

    t3 = -1 / float(n1)
    r = pow(t1 + t2, t3)
    if abs(r) == 0:
        return (0, 0)
      #     return (r * cos(phi), r * sin(phi))
        return (r, phi)

def supershape(width, height, m, n1, n2, n3,
               point_count=10 * 1000, percentage=1.0, a=1.0, b=1.0, travel=None):
    '''Supershape, generated using the superformula first proposed 
    by Johan Gielis.

    - `points_count` is the total number of points to compute.
    - `travel` is the length of the outline drawn in radians. 
       3.1416 * 2 is a complete cycle.
    travel = travel or (10 * 2 * pi)

    # compute points...
    phis = [i * travel / point_count
            for i in range(1 + int(point_count * percentage))]
    points = [superformula_polar(a, b, m, n1, n2, n3, x) for x in phis]

    # scale and transpose...
    path = []
    for r, a in points:
        x = width * r * cos(a)
        y = height * r * sin(a)
        path.append(Coordinate(x, y))

    return Path(path)


if __name__ == '__main__':

    override = False

    plt = instantiate_plotters()[0]
#   plt.write('IN;')

    if plt.margins.soft.width < 11000:               # A=10365 B=16640
        maxplotx = (plt.margins.soft.width / 2) - 100
        maxploty = (plt.margins.soft.height / 2) - 150
        legendx = maxplotx - 2600
        legendy = -(maxploty - 650)
        tscale = 0.45
        numpens = 4
        # prime/10 = number of spikes
        m_values = [n / 10.0 for n in [11, 13, 17, 19, 23]]
        # ring-ness 0.1 to 2.0, higher is larger
        n1_values = [
            n / 100.0 for n in range(55, 75, 2) + range(80, 120, 5) + range(120, 200, 10)]
        maxplotx = plt.margins.soft.width / 2
        maxploty = plt.margins.soft.height / 2
        legendx = maxplotx - 3000
        legendy = -(maxploty - 700)
        tscale = 0.45
        numpens = 6
        m_values = [n / 10.0 for n in [11, 13, 17, 19, 23, 29, 31,
                                       37, 41, 43, 47, 53, 59]]   # prime/10 = number of spikes
        # ring-ness 0.1 to 2.0, higher is larger
        n1_values = [
            n / 100.0 for n in range(15, 75, 2) + range(80, 120, 5) + range(120, 200, 10)]

    print "   Max: ({},{})".format(maxplotx, maxploty)

    # spiky-ness 0.1 to 2.0, lower is spiky-er
    n2_values = [
        n / 100.0 for n in range(10, 60, 2) + range(65, 100, 5) + range(110, 200, 10)]

    plt.write(chr(27) + '.H200:')   # set hardware handshake block size
    # scale based on B size characters
    plt.write(hpgl.SI(tscale * 0.285, tscale * 0.375))
    # slow speed for those abrupt spikes
    while True:
        # standard loadout has pen 1 = fine black
        plt.write(hpgl.PA([(legendx, legendy)]))
        plt.write(hpgl.LB("Started " + str(

        if override:
            m = 4.1
            n1_list = [1.15, 0.90, 0.25, 0.59, 0.51, 0.23]
            n2_list = [0.70, 0.58, 0.32, 0.28, 0.56, 0.26]
            m = random.choice(m_values)
            n1_list = random.sample(n1_values, numpens)
            n2_list = random.sample(n2_values, numpens)

        pen = 1
        for n1, n2 in zip(n1_list, n2_list):
            n3 = n2
            print "{0} - m: {1:.1f}, n1: {2:.2f}, n2=n3: {3:.2f}".format(pen, m, n1, n2)
            plt.write(hpgl.PA([(legendx, legendy - 100 * pen)]))
                hpgl.LB("Pen {0}: m={1:.1f} n1={2:.2f} n2=n3={3:.2f}".format(pen, m, n1, n2)))
            e = supershape(maxplotx, maxploty, m, n1, n2, n3)
            pen = pen + 1 if (pen % numpens) else 1

        plt.write(hpgl.PA([(legendx, legendy - 100 * (numpens + 1))]))
        plt.write(hpgl.LB("Ended   " + str(
        print "Waiting for plotter... ignore timeout errors!"
        while NoneType is type(plt.status):

        print "Load more paper, then ..."
        print "  ... Press ENTER on the plotter to continue"
        plotstatus = plt.status
        while (NoneType is type(plotstatus)) or (0 == int(plotstatus) & 0x04):
            plotstatus = plt.status
        print "Digitized: " + str(plt.digitized_point)