Categories
goatee-stroking musing, or something

card for my mother-in-law, who is feeling a bit isolated right now #glint

open envelope with blue and red block printed "printer's flowers" ornaments, aka glint
3d printed Glint block printing at roughly 72pt
Categories
goatee-stroking musing, or something

Arduino Nano “Dead Bug” Case

Arduino Nano in 3d printed case with pin label
Arduino Nano in 3d printed case with pin label

I like Arduino Nanos. They’re cheap. They work. They’re small. But they’re a bit fiddly, what with their breadboard legs and tiny pin labels. Wouldn’t it be nicer to use them as self-contained units, with Dupont wires coming from the pins?

This is where nspohrer’s Arduino Nano case with completely accessible pins comes in:

Arduino Nano case with completely accessible pins, from Thingiverse
Arduino Nano case with completely accessible pins, from Thingiverse

Flip it over, label the pins, and you’ve got a polished little microcontroller in a box. And do I have just the right label for you …

Reversed Arduino Nano pin label
Reversed Arduino Nano pin label
(PDF behind the linked image)

I’ve even included the original SVG so you can make custom versions. Please ignore the “micro” in the name … they are really for the Nano.

Arduino Micro label
no, really … this is an Arduino Micro label for the appropriate case on Thingiverse

Categories
computers suck

Stand for PROTODOME’s 4000AD chiptune album

4000AD album PCB in stand, with Print+ 3D printed headphones in foreground

So Dr. Blake “PROTODOME” Troise (previously) made a chiptune album that’s entirely synthesized by an Atmel/Microchip ATmega328P microcontroller in realtime. And every chip needs a PCB, right? So Blake released the album as a physical device you can solder up for yourself.

Of course, having the PCB lying flat doesn’t allow you to see Marianne Thompson’s great pixel cover art, or read the liner notes on the back — and risks having the circuit short out on random tinny things on your desk. (Maybe that’s just my desk, though.)

This stand allows you to display the board at a convenient 75° angle, but also allows the PCB to be flipped forward so you can read the liner notes comfortably. Yeah, I may have been a crate-digger at one time.

Links:

(or Thingiverse link: https://www.thingiverse.com/thing:4579706)

4000AD album PCB in stand, front view
4000AD album PCB in stand, rear view (messy Kapton taping optional)
4000AD album PCB stand in black low-sheen PLA
Categories
goatee-stroking musing, or something

Glint

geometric pattern made from two floral type ornaments designed by David Bethel
my first decent vector rendering of David Bethel’s “Glint” typographic ornaments (Monotype B1309 & B1310, 1956)

I’m really enjoying Elisabeth Fraser’s The Glint Game, a delightfully nerdy pattern diversion that uses real metal type.

squared pad with floral imprints and metal type in plastic holders
18pt Glint Game from Frauhaus
Categories
amateur radio computers suck

calculator for engineering nerds

For something to do with my head, I’m taking the RAC Advanced Ham Radio course. The exam uses a non-programmable scientific calculator. I thought that all my calculators were programmable, but we found this one lurking in the basement and it’s just perfect:

Casio fx-115MS scientific calculator
SI prefixes above 1…9 on the fx-115MS: f, p, n µ, m, k, M, G, T

This is one of the few calculators I’ve seen that both displays and takes inputs in SI units. How to put it into SI engineering display mode is explained in this delightful (archived) site Casio fx-115MS.

Entering numbers with SI prefixes is simple: type the number, then Shift and hit the prefix. So to enter 300000, you’d type 300 Shift 4 to get 300 k.

You do have to be a little careful reading the display in this mode, though. The display above reads 221 × 10-3 (from the m at right), or 0.221.

I don’t see any calculator in Casio’s current range that offers this handy feature. Guess I’m lucky I found it before the exam!

Categories
computers suck goatee-stroking musing, or something

speech on Raspberry Pi: espeak-ng

Audio can be a bit dismal on a Raspberry Pi. Once you get a configuration that works, sometimes you’re not sure how you got there and you’ll do anything to keep that arcane setup going. It’s better than it was.

Speech synthesis or TTS adds an extra layer for potential failure. One of the popular Linux TTS systems, eSpeak, hasn’t seen much development in almost a decade and seems to only work through workarounds and hand-waving.

Thankfully, there’s a fork of eSpeak that is maintained: espeak-ng. Better yet, it’s packaged with Raspberry Pi OS and can be installed quite easily:

sudo apt install espeak-ng espeak-ng-data libespeak-ng-dev

In my simple tests, it output everything I expected of it.

eSpeak had a Python module that kinda worked, but espeak-ng’s is much more ambitious, and (mostly) does what it sets out to do. You can install it like this:

sudo pip3 install py-espeak-ng

py-espeak-ng has some documentation, but it’s still got some trial and error in getting it to work. The biggest issue that held me up was that the module needs to be initialized with a voice that espeak-ng already knows about. If you don’t specify a voice, or specify one that the system doesn’t know about, you won’t get any errors — but you won’t get any output, either.

Here’s a small Python example that you’ll probably want to try with no-one else within earshot. It repeats the same English phrase (a favourite of elocution teachers) in every English regional language that espeak-ng knows about. In addition, since I’m a dictionary nerd, it outputs phonetics too.

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# an espeakng elocution lesson from scruss, 2020-07
#     I suffered this at school, now you get to as well!
# You will need to:
#     sudo apt install espeak-ng espeak-ng-data libespeak-ng-dev
#     sudo pip3 install py-espeak-ng

from espeakng import ESpeakNG
from time import sleep

# you have to initialize with a voice that exists
#   `espeak-ng --voices=en` will list English ones
esng = ESpeakNG(voice='en-gb')
esng.pitch = 32
esng.speed = 150

phrase = "Father's car is a Jaguar and pa drives rather fast. "\
    "Castles, farms and draughty barns, all go charging past."
print(phrase)
print()

for voice in esng.voices:
    if voice['language'].startswith('en-'):
        print('Using voice:', voice['language'],
              'for', voice['voice_name'], '-')
        esng.voice = voice['language']
        ipa = esng.g2p(phrase, ipa=2)
        print(voice['language'], 'phonetics:', ipa)
        esng.say(phrase, sync=True)
        print()
        sleep(0.1)

Be thankful you can’t hear the output. The IPA output, however, is a thing of beauty:

./espeakNG_test.py
Father's car is a Jaguar and pa drives rather fast. Castles, farms and draughty barns, all go charging past.

Using voice: en-029 for English_(Caribbean) -
en-029 phonetics: fˈɑːdaz kˈɑ͡əɹ ɪz a d͡ʒˈaɡwɑ͡ə and pˈɑː dɹˈa͡ɪvz ɹˈɑːda fˈa͡astkˈa͡asɛlzfˈɑ͡əmz and dɹˈa͡afti bˈɑ͡ənzˈɔːl ɡˌo͡ʊ t͡ʃˈɑ͡əd͡ʒɪn pˈa͡ast

Using voice: en-gb for English_(Great_Britain) -
en-gb phonetics: fˈɑːðəz kˈɑːɹ ɪz ɐ d͡ʒˈaɡwɑː and pˈɑː dɹˈa͡ɪvz ɹˈɑːðə fˈastkˈasə͡lzfˈɑːmz and dɹˈafti bˈɑːnzˈɔːl ɡˌə͡ʊ t͡ʃˈɑːd͡ʒɪŋ pˈast

Using voice: en-gb-scotland for English_(Scotland) -
en-gb-scotland phonetics: fˈa:ðɜz kˈaːr ɪz ɐ d͡ʒˈaɡwaːr and pˈa: drˈa͡ɪvz rˈa:ðɜ fˈa:stkˈa:sə͡lzfˈaːrmz and drˈa:fte bˈaːrnzˈɔːl ɡˌoː t͡ʃˈaːrd͡ʒɪŋ pˈa:st
 …

Categories
goatee-stroking musing, or something

The Mandelbrot Set, before Mandelbrot

How many CPU hours did I burn in the early 1990s rendering bits of the Mandelbrot Set? A lot, mainly because I was doing it in BASIC on an unexpanded 8 MHz Commodore Amiga A500. The image below that Fraqtive rendered in almost no time would have taken me days:

the squashed bug that started it all: the Mandelbrot set

But it turns out that the first rendering of what we now call the Mandelbrot set wasn’t produced by Benoit Mandelbrot, but by Brooks & Matelski a year or two earlier:

text plot of the Mandelbrot set with points inside set marked with asterisks
figure 2 (original caption “The set of C’s such that f(z) = z² + C has a stable periodic orbit”) from Brooks, Robert, and J. Peter Matelski. “The dynamics of 2-generator subgroups of PSL (2, C).Riemann surfaces and related topics: Proceedings of the 1978 Stony Brook Conference, Ann. of Math. Stud. Vol. 97. 1981.

What I’ve tried to do — and come close, but not actually managed to exactly replicate — is create period-appropriate code to reproduce that graphic. Since the paper was presented in 1978, there’s a fair chance that the authors had access to a machine running FORTRAN-77 or a near equivalent. FORTRAN’s particularly good for this:

  • it has a built-in COMPLEX type that extends regular mathematical functions;
  • it has just good enough string handling to output a line of spaces/asterisks. I would not have wanted to write this in FORTRAN-66, as that language had no string manipulation facilities at all.

So here’s the code. It should compile on any Fortran compiler:

      PROGRAM BRKMAT
! GENERATE FIGURE FROM BROOKS-MATELSKI PAPER C.1978
!  THAT EVENTUALLY BECAME KNOWN AS THE MANDELBROT SET
! - SCRUSS, 2020-06
! REF: BROOKS, ROBERT, AND J. PETER MATELSKI.
!     "THE DYNAMICS OF 2-GENERATOR SUBGROUPS OF PSL (2, C)."
!      RIEMANN SURFACES AND RELATED TOPICS: PROCEEDINGS OF THE
!      1978 STONY BROOK CONFERENCE,
!      ANN. OF MATH. STUD. VOL. 97. 1981: FIG. 2, P. 81

         REAL MAP, CR, CI
         INTEGER I, J, K, M, ROWS, COLS, MAXIT
         COMPLEX C, Z
         PARAMETER (ROWS=31, COLS=70, MAXIT=36)
         CHARACTER*80 OUT
         CHARACTER CH*1

         DO J=1,ROWS
            CI=MAP(REAL(J), 1.0, REAL(ROWS), -0.89, 0.89)
            DO I=1,COLS
               CR=MAP(REAL(I), 1.0, REAL(COLS), -2.0, 0.45)
               C=CMPLX(CR, CI)
               Z=CMPLX(0.0, 0.0)
               CH='*'
               DO 100, K=1,MAXIT
                  Z = Z**2 + C
                  IF (ABS(Z) .GT. 2) THEN
                     CH=' '
                     GO TO 101
                  END IF
 100           CONTINUE
 101           OUT(I:I)=CH
            END DO
            WRITE(*,*)OUT
         END DO
      END

      REAL FUNCTION MAP(X, XMIN, XMAX, YMIN, YMAX)
         REAL X, XMIN, XMAX, YMIN, YMAX
         MAP = YMIN + (YMAX - YMIN) * ((X - XMIN) / (XMAX - XMIN))
      END

The results are close:

mandelbrot set, rendered in asterisks from BRKMAT.F
a few more holes in this than the original

but not quite right. Maybe Brooks & Matelski had access to an Apple II and wrote something in BASIC? I could be entirely period-accurate and write something in PDP-8 BASIC on my SBC6120, but not today.

It really is much easier using a language with complex number support when working with the Mandelbrot set. Here’s the same program in Python3, which bears more of a resemblance to FORTRAN-77 than it might admit:

#!/usr/bin/python3
# brkmat - Brooks-Matelski proto ASCII Mandelbrot set - scruss, 2020-06
# -*- coding: utf-8 -*-

def valmap(value, istart, istop, ostart, ostop):
    return ostart + (ostop - ostart) * ((value - istart) / (istop - istart))

rows = 31
cols = 70
maxit = 36

for y in range(rows):
    ci = valmap(float(y + 1), 1.0, float(rows), -0.89, 0.89)
    for x in range(cols):
        cr = valmap(float(x + 1), 1.0, float(cols), -2.0, 0.45)
        c = complex(cr, ci)
        z = complex(0.0, 0.0)
        ch = '*'
        for k in range(maxit):
            z = z**2 + c
            if (abs(z) > 2.0):
                ch = ' '
                break
        print(ch, end='')
    print()

I found out about the Brooks-Matelski paper from this article: Who Discovered the Mandelbrot Set? – Scientific American. It’s none too complimentary towards Benoit Mandelbrot.

Categories
computers suck

yet another homage …

So it turns out that Mines Incas is yet another variant on 2D Star Dodge / Asterisk Tracker theme. And it’s really well done!

Play it in your browser: Mines Incas

Info page at CPC-POWER: Mines Incas

Categories
goatee-stroking musing, or something

MicroPython on the BrainPad Classic/BP2

GHI Electronics BrainPad Classic/BP2 electronics project board on a tasteful faux-leopard background. Small OLED screen is showing "SCRUSS 2020"
GHI Electronics BrainPad Classic/BP2 in 3d printed case

I’ve extended the MicroPython examples for the BrainPad Classic so that all of the devices work: scruss/brainpad-micropython: Micropython examples for the BrainPad Classic (BP2) from GHI Electronics.

The ones that already worked in the original examples repo are:

  • buttons
  • accelerometer
  • LEDs
  • light sensor
  • OLED screen

I’ve added:

  • temperature sensor: although my calibration may be a bit off on the MCP9701a used on the board
  • timer blink example: STM32 Timers are cool and we should use them
  • PWM RGB LED example: floating-point silliness with HSV(ish) Colour Wheel in Python
  • buzzer: simple tones plus tunes (in RTTTL) via dhylands / upy-rtttl
  • servos: I may have forgotten to put the example in there, but the standard Servo(1) code should work.

Yes, it would be nice to have a slick unified library like the BBC micro:bit does. For later, though.

Other resources:

Categories
photo

godspeed, Edouard LeBlanc

godspeed, Edouard LeBlanc

Instagram filter used: Normal

View in Instagram ⇒

Categories
photo

mood

mood

Instagram filter used: Lo-fi

View in Instagram ⇒

Categories
photo

virtual potato print

virtual potato print

Instagram filter used: Normal

View in Instagram ⇒

Categories
photo

mornin’

mornin’

Instagram filter used: Lo-fi

View in Instagram ⇒

Categories
photo

groundhog!

nomming from our deck

Categories
goatee-stroking musing, or something

terminal colour silliness with Python

terminal text in rainbows

Using ansicolors:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
# colourshen.py - stdin to rainbow stdout
# scruss, 2020-06

from colors import *            # see https://pypi.org/project/ansicolors/
import sys
wheel_pos = 0


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))


def hex_wheel(pos):
    rgb = cos_wheel(pos)
    return('#%02x%02x%02x' % rgb)


def wheel_print(s):
    global wheel_pos
    incr = int(256/(1+len(s)))-1
    if incr < 1:
        incr = 1
    for c in s:
        print(color(c, fg=hex_wheel(wheel_pos)), end='')
        wheel_pos = (wheel_pos+incr) % 256
    print()


for txt in sys.stdin:
    wheel_print(txt.rstrip())

(fixed a very obvious ahem! in the code, hope no-one noticed …)

Categories
photo

groundhog helps with the pruning

groundhog helps with the pruning

Instagram filter used: Normal

View in Instagram ⇒

groundhog helps with the pruning
Categories
photo

MÖNCH

MÖNCH

Instagram filter used: Normal

View in Instagram ⇒

Categories
goatee-stroking musing, or something

mandala with chips

8-way symmetric constructed mandala on a black background with small unencapsulated silicon chips placed as jewels every 45°
graphite, pencil crayons, silicon chips
small rectangular silicon chip sitting on gold graphite background
detail at 600 dpi. I have lots of these.
Categories
photo

fortran made a stripey one

fortran made a stripey one

Instagram filter used: Normal

View in Instagram ⇒

Categories
photo

chips with everything

chips with everything

Instagram filter used: Normal

View in Instagram ⇒