Just what 2019 needs: the QBasic Online Help Index

QBasic (from olddos.exe) running nicely under dosbox on Linux

Only umpteen years late, I bring you the

QBasic Online Help Indexhttps://scruss.com/qbasic_hlp/

It’s the QuickHelp file from Microsoft’s ancient-but-still-useful QBasic interpreter for MS-DOS. I converted it to HTML, and made some minor cleanups so it would work better on the web.

So if you’ve got a hankering to understand the parameters for MKSMBF$ or know the syntax of PRINT USING, I’ve got your back.

gleeful bash scripting: contrived GCD function

The greatest common divisor (gcd) of two natural numbers is the largest number that evenly divides both. For instance gcd(8, 12) is 4. There are many clever and efficient ways to calculate the gcd of two numbers on a Linux machine. The method presented here is not among them.

#!/bin/bash
gcd(){ comm -12 --nocheck-order <(factor $1|sed 's/^[^ ]*/1/;s/ /\n/g') <(factor $2|sed 's/^[^ ]*/1/;s/ /\n/g')|tr '\n' \*|sed 's/.$/\n/'|bc;}
gcd $1 $2

(Contrived) example:

gcd.sh 24691357802469135780246913578 61728394506172839450617283945
12345678901234567890123456789

Which breaks down as:

prime factors of
24691357802469135780246913578
prime factors of
61728394506172839450617283945
2 
33
33
33
 5
77
1313
3131
3737
211211
241241
21612161
36073607
38033803
29061612906161

Multiply the factors common to both:

3 × 3 × 3 × 7 × 13 × 31 × 37 × 211 × 241 × 2161 × 3607 × 3803 × 2906161 = 12345678901234567890123456789

I’m sure someone else has used the output of factor and comm in this way before. The hard part was getting coprime numbers to output 1.

Digital Photo Archaeology: featuring hardware DRM from the crypt

So I picked up this large boy from the MSU Surplus Store:

Sony Digital Mavica MVC-FD91 (c. 1998 CE) — yes, that’s a 3½” floppy drive on there

You get about 7 high-resolution pictures on a disk. And high resolution by 1998 standards means this:

1024×768 whole pixels: that’s huge! The camera is autofocus with image stabilization, so it was quite a nifty unit at the time.

Pre-dating EXIF, its image metadata is limited. There’s an external ‘411’ thumbnail file that looks a bit like this:

If you care to dig about in such an ancient file, I’ve got a matching image and its 411 file here: MVC-005X.zip. And manuals? Here: Sony_Mavica-FDC91-W0007229M.pdf

Most annoyingly, the camera really only likes real Sony batteries, or it shuts down with an “InfoLithium” battery error. As this battery format is now used in generate photo lighting systems and Sony don’t make it any more, this may be a camera that dies from DRM before anything else.

HSV(ish) Colour Wheel in Python

Years back I wrote something about HSV colour cycling for Arduino. Things have moved on: we’re all writing code in MicroPython/CircuitPython now and 8-bit micro-controllers are looking decidedly quaint. Yes, yes; some of you must still write code in PIC assembly language and I’m sure that’s very lovely for you indeed don’t @ me.

If you look at the output of a typical HSV to RGB algorithm, the components map something like this:

Hue between 0-1, with saturation and value set to 1. Output range 0-1 for each component

These lines remind me so much of sine waves, if very blocky ones. The red trace in particular is just the cosine function, with the input range of 0..2π and the output range of -1..1 both mapped to 0..1. The green and blue traces are just the red trace shifted horizontally by ⅓ and ⅔ respectively.

Since we have transcendental functions in MicroPython, we don’t have to fossick about with linear approximations. The common RGB LED function wheel() uses similar linear interpolation as the graph above. Why make do with blocky cogwheels when you can have a smooth colour wheel?

def cos_wheel(pos):
# Input a value 0 to 255 to get a colour value.
# scruss (Stewart Russell) - 2019-03 - CC-BY-SA
from math import cos, pi
if pos < 0:
return (0, 0, 0)
pos %= 256
pos /= 255.0
return (int(255 * (1 + cos( pos * 2 * pi)) / 2),
int(255 * (1 + cos((pos - 1 / 3.0) * 2 * pi)) / 2),
int(255 * (1 + cos((pos - 2 / 3.0) * 2 * pi)) / 2))
Though you never quite get a pure red, green or blue, the results are pleasing

Quite elegant, I thought. Yeah, it may be computationally expensive, but check next year when we’ll all be running even faster µcs. Certainly none of the mystery switch statements or nested conditionals you’ll see in other code. Just maths, doing its thing.

First half is cosine wheel, second half (after red flash) is linear

Invented right here: the T-Nut

from US Patent 3480061 ‘Fastener member’ by W. H. Leistner, granted 1969-11-25

Simple things like fasteners don’t seem to be invented. It’s almost as if they’ve always been around. Like T-nuts — those hammer-in furniture nuts that also find use as 3D printable tripod mounts — someone invented those?

Sure enough, it seems that local company Sigma Tool & Machine have a lot to do with T-nut development. They’re now on Nantucket Blvd just north of me, and they used to be at 96 Crockford Blvd very close by.

Symmetric chamfered extrusion in OpenSCAD

enjoy the quality of the smooth, smooth taper

I like using OpenSCAD, but it has some limitations. While you can linear_extrude() 2D paths into 3D shapes, you can’t get a proper tapered/chamfered extrusion of anything but simple shapes that are symmetric about the origin:

// this is symmetrical …
linear_extrude(height=20, scale=2)square(10, center=true);

// but shift the same square off the origin and this happens …
linear_extrude(height=20, scale=2)translate([20, 20])square(10, center=true);

There are lots of partial attempts at fixing this, many of which end up with ugly results. Some of them even mess up the top surface, which is precisely what I wanted to avoid. My code uses the computationally-intensive minkowski() sum function to replace every vertex of a 2D shape with a many-sided pyramid.

Minkowski sums effectively replace every vertex with another shape, here making a rounded cube from a cube and a sphere:

minkowski() {
cube(10);
sphere(4);
}

One feature of OpenSCAD’s implementation of the Minkowski sum is that the operator takes into account the second shape’s position relative to the origin. So if I take the same cube and apply the minkowski() operator with the same sphere moved away from the origin, I get:

// the same cube, but shifted by the power of minkowski()!
minkowski() {
cube(10);
translate([-15,-15,-15])sphere(4);
}

So I can approximate a tapered extrusion by turning a 2d path into a very thin 3d plate (OpenSCAD’s 2D and 3D subsystems can never meet in the same output) and using a pyramid as the second argument to the operator:

// the component parts, before minkowski()

// thin extrusion of 2D path
linear_extrude(height=0.001)text(“S”, size=24, font=”EB Garamond:style=12 Italic”);

// a 30 degree pyramid with its apex at the origin
rotate_extrude()polygon([ [0,0] , [4, -8], [0, -8] ]);

You get:

minkowski() {
// thin extrusion of 2D path
linear_extrude(height=0.001)text(“S”, size=24, font=”EB Garamond:style=12 Italic”);
// a 30 degree pyramid with its apex at the origin
rotate_extrude()polygon([ [0,0] , [4, -8], [0, -8] ]);
}

In reality, you’d probably use a smaller taper angle, but the example is short rather than pretty. If you’re really picky about correctness, the process leaves the thin extrusion as parallel walls at the bottom of the shape, shown grossly exaggerated here for effect:

hugely exaggerated vertical profile

If you’re working in consumer-grade 3D printing and are using the standard 1 unit = 1 mm scale, the residual parallel section would only be 1 µm thick and way below any realistic layer height. Feel free to remove it, but be warned that this process creates so many facets that the difference() required to remove it will be very time-consuming for no visible difference.

Here’s the code: chamfer_extrude.scad – make sure to rename the txt extension to scad. Or, if you’d prefer, here’s a link to a gist: scruss/chamfer_extrude.scad

Put it in your OpenSCAD library folder, then you can use it like this:

include <chamfer_extrude.scad>; 

chamfer_extrude(height=4, angle=15, $fn=16)text("S", size=24, font="EB Garamond:style=12 Italic", $fn=64);
way smooth s

The library just adds some expected utility and tidiness to the above process. The source includes documentation and examples.

The Quirkey: chording USB keyboard

This may not look much, but it’s a test build of Vik Olliver’s Quirkey USB chord keyboard. I didn’t quite build it to Vik’s specs, which are here:

The Microwriter was a late 1970s/early 1980s gadget that was essentially a portable word processor. Unusually, its keyboard was a single-hand 6 key layout — the thumb did double duty — that was operated by chording multiple keys at the same time. Later on in the Microwriter’s life it evolved into the Quinkey, a chording adaptive keyboard for computers of the time.

Technology has moved on a bit, and the ability to wire up a cheap USB-capable microcontroller and 3d print your own case is here. I used an Arduino Micro on a breadboard and six Omron momentary buttons.

I didn’t quite wire it the way that Vik intended:

Note lifted pins to prevent useless buttons

The buttons are wired like this:

Pin      Button
======= =======
D8 Control
D7 Thumb
D6 Index
D5 Middle
D4 Ring
D3 Pinkie

This requires changing line 22 of Vik’s code from:

const int keyPorts[] = {8, 7, 6, 5, 4, 9};

to

const int keyPorts[] = {8, 3, 4, 5, 6, 7};

While there are great tutorials on “microwriting” in the original manuals on Bill Buxton’s site, here are the basic alphabetic set derived from Vik’s code:

Thumb
|Index
||Middle
|||Ring
||||Pinkie
●○○○○ : Space
○●○○○ : e
●●○○○ : i
○○●○○ : o
●○●○○ : c
○●●○○ : a
●●●○○ : d
○○○●○ : s
●○○●○ : k
○●○●○ : t
●●○●○ : r
○○●●○ : n
●○●●○ : y
○●●●○ : .
●●●●○ : f
○○○○● : u
●○○○● : h
○●○○● : v
●●○○● : l
○○●○● : q
●○●○● : z
○●●○● : -
●●●○● : '
○○○●● : g
●○○●● : j
○●○●● : ,
●●○●● : w
○○●●● : b
●○●●● : x
○●●●● : m
●●●●● : p

The astute reader may note that these are binary values (low bit to high) of the character positions in Vik’s alphaTable variable. And yes, that’s supposed to be preformatted text.

Happy microwriting!

Tact & Buttons

The right and wrong ways to connect buttons

Buttons, Tactile switches, Momentaries, Clickies, SPST-NO; call ’em what you will, but my world seems to be full of them right now. Wiring them or breadboarding them may not be as simple as they look.

Whether they are the tiny 6 mm ones of the less-easily-lost 12 mm ones, both types typically have four pins or legs, two on the top and two on the bottom. If your appear to have the legs on the sides, flip ’em 90°: they won’t fit in breadboard sockets the wrong way.

The pins on the left and right side are common, so connecting top left to bottom left won’t ever change state if you press the button. So use either the pins both on the same side or those diagonally opposed if you want the switch to work.

You can use these buttons on a common breadboard rail. You must remember to have only one button pin connecting to the rail; lift the other pin so it won’t connect. You can then use just one wire connected diagonally across the the common rail pin and you’ve got a working button. This is especially useful when using a microcontroller with built-in pull up resistors (that’s most of them these days).

If you connect both pins to a common rail, you’ve just made a SPST-AO (single pole, single throw – always open) switch. Those aren’t much use at all.