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!"
sleep(40)
while NoneType is type(plt.status):
sleep(5)
print "Load more paper, then ..."
print " ... Press ENTER on the plotter to continue"
plt.clear_digitizer()
plt.digitize_point()
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:

The Sakura pens in their adapters continue to work well:

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.
see: http://en.wikipedia.org/wiki/Superformula
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)
else:
# 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)
# RUN DEMO CODE
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)]
else:
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
plt.set_origin_center()
# scale based on B size characters
plt.write(hpgl.SI(tscale * 0.285, tscale * 0.375))
# slow speed for those abrupt spikes
plt.write(hpgl.VS(10))
while True:
# standard loadout has pen 1 = fine black
plt.write(hpgl.PA([(legendx, legendy)]))
plt.select_pen(1)
plt.write(hpgl.LB("Started " + str(datetime.today())))
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]
else:
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.select_pen(pen)
plt.write(hpgl.PA([(legendx, legendy - 100 * pen)]))
plt.write(
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)
plt.write(e)
pen = pen + 1 if (pen % numpens) else 1
plt.select_pen(1)
plt.write(hpgl.PA([(legendx, legendy - 100 * (numpens + 1))]))
plt.write(hpgl.LB("Ended " + str(datetime.today())))
plt.select_pen(0)
plt.write(hpgl.PA([(-maxplotx,maxploty)]))
print "Waiting for plotter... ignore timeout errors!"
sleep(40)
while NoneType is type(plt.status):
sleep(5)
print "Load more paper, then ..."
print " ... Press ENTER on the plotter to continue"
plt.clear_digitizer()
plt.digitize_point()
plotstatus = plt.status
while (NoneType is type(plotstatus)) or (0 == int(plotstatus) & 0x04):
plotstatus = plt.status
print "Digitized: " + str(plt.digitized_point)
Comments
2 responses to “HP 7475A Plotter: One-Button Demo Madness”
[…] out tchochkes, and generally talking myself hoarse. The HP 7475A plotter will be cranking out Superforumulas next door, too, because everybody loves watching a […]
[…] general idea was to put the old Lenovo Q150 to work as a dedicated Superformula generator attached to the HP 7475A plotter: connect the serial cable, fire ’em up, and It Just Works. […]