Tag: annoying

  • Crickets in February

    It’s mid-February in Toronto: -10 °C and snowy. The memory of chirping summer fields is dim. But in my heart there is always a cricket-loud meadow.

    Short of moving somewhere warmer, I’m going to have to make my own midwinter crickets. I have micro-controllers and tiny speakers: how hard can this be?

    more fun than a bucket of simulated crickets
    (video description: a plastic box containing three USB power banks, each with USB cable leading to a Raspberry Pi Pico board. Each board has a small electromagnetic speaker attached between ground and a data pin)

    I could have merely made these beep away at a fixed rate, but I know that real crickets tend to chirp faster as the day grows warmer. This relationship is frequently referred to as Dolbear’s law. The American inventor Amos Dolbear published his observation (without data or species identification) in The American Naturalist in 1897: The Cricket as a Thermometer

    journal text:

The rate of chirp seems to be entirely determined by the temperature and this to such a degree that one may easily compute the temperature when the number of chirps per minute is known.

Thus at 60° F. the rate is 80 per minute.

At 70° F. the rate is 120 a minute, a change of four chirps a minute for each change of one degree. Below a temperature
of 50° the cricket has no energy to waste in music and there would be but 40 chirps per minute.
One may express this relation between temperature and chirp rate thus.
Let T. stand for temperature and N,  the rate per minute.

(typeset equation)
T. = 50 + (N - 40) / 4
    pretty bold assertions there without data eh, Amos old son …?

    When emulating crickets I’m less interested in the rate of chirps per minute, but rather in the period between chirps. I could also care entirely less about barbarian units, so I reformulated it in °C (t) and milliseconds (p):

    t = ⅑ × (40 + 75000 ÷ p)

    Since I know that the micro-controller has an internal temperature sensor, I’m particularly interested in the inverse relationship:

    p = 15000 ÷ (9 * t ÷ 5 – 8)

    I can check this against one of Dolbear’s observations for 70°F (= 21⅑ °C, or 190/9) and 120 chirps / minute (= 2 Hz, or a period of 500 ms):

    p = 15000 ÷ (9 * t ÷ 5 – 8)
       = 15000 ÷ (9 * (190 ÷ 9) ÷ 5 – 8)
       = 15000 ÷ (190 ÷ 5 – 8)
       = 15000 ÷ 30
       = 500

    Now I’ve got the timing worked out, how about the chirp sound. From a couple of recordings of cricket meadows I’ve made over the years, I observed:

    1. The total duration of a chirp is about ⅛ s
    2. A chirp is made up of four distinct events:
      • a quieter short tone;
      • a longer louder tone of a fractionally higher pitch;
      • the same longer louder tone repeated;
      • the first short tone repeated
    3. There is a very short silence between each tone
    4. Each cricket appears to chirp at roughly the same pitch: some slightly lower, some slightly higher
    5. The pitch of the tones is in the range 4500–5000 Hz: around D8 on the music scale

    I didn’t attempt to model the actual stridulating mechanism of a particular species of cricket. I made what sounded sort of right to me. Hey, if Amos Dolbear could make stuff up and get it accepted as a “law”, I can at least get away with pulse width modulation and tiny tinny speakers …

    This is the profile I came up with:

    • 21 ms of 4568 Hz at 25% duty cycle
    • 7 ms of silence
    • 28 ms of 4824 Hz at 50% duty cycle
    • 7 ms of silence
    • 28 ms of 4824 Hz at 50% duty cycle
    • 7 ms of silence
    • 21 ms of 4568 Hz at 25% duty cycle
    • 7 ms of silence

    That’s a total of 126 ms, or ⅛ish seconds. In the code I made each instance play at a randomly-selected relative pitch of ±200 Hz on the above numbers.

    For the speaker, I have a bunch of cheap PC motherboard beepers. They have a Dupont header that spans four pins on a Raspberry Pi Pico header, so if you put one on the ground pin at pin 23, the output will be connected to pin 26, aka GPIO 20:

    Raspberry Pi Pico with small piezo speaker connected to pins 23 (ground) and 26 (GPIO 20)
    from a post where I did a very, very bad thing: Nyan Cat, except it gets faster — RTTTL on the Raspberry Pi Pico

    So — finally — here’s the MicroPython code:

    # cricket thermometer simulator - scruss, 2024-02
    # uses a buzzer on GPIO 20 to make cricket(ish) noises
    # MicroPython - for Raspberry Pi Pico
    # -*- coding: utf-8 -*-
    
    from machine import Pin, PWM, ADC, freq
    from time import sleep_ms, ticks_ms, ticks_diff
    from random import seed, randrange
    
    freq(125000000)  # use default CPU freq
    seed()  # start with a truly random seed
    pwm_out = PWM(Pin(20), freq=10, duty_u16=0)  # can't do freq=0
    led = Pin("LED", Pin.OUT)
    sensor_temp = machine.ADC(4)  # adc channel for internal temperature
    TOO_COLD = 10.0  # crickets don't chirp below 10 °C (allegedly)
    temps = []  # for smoothing out temperature sensor noise
    personal_freq_delta = randrange(400) - 199  # different pitch every time
    chirp_data = [
        # cadence, duty_u16, freq
        # there is a cadence=1 silence after each of these
        [3, 16384, 4568 + personal_freq_delta],
        [4, 32768, 4824 + personal_freq_delta],
        [4, 32768, 4824 + personal_freq_delta],
        [3, 16384, 4568 + personal_freq_delta],
    ]
    cadence_ms = 7  # length multiplier for playback
    
    
    def chirp_period_ms(t_c):
        # for a given temperature t_c (in °C), returns the
        # estimated cricket chirp period in milliseconds.
        #
        # Based on
        # Dolbear, Amos (1897). "The cricket as a thermometer".
        #   The American Naturalist. 31 (371): 970–971. doi:10.1086/276739
        #
        # The inverse function is:
        #     t_c = (75000 / chirp_period_ms + 40) / 9
        return int(15000 / (9 * t_c / 5 - 8))
    
    
    def internal_temperature(temp_adc):
        # see pico-micropython-examples / adc / temperature.py
        return (
            27
            - ((temp_adc.read_u16() * (3.3 / (65535))) - 0.706) / 0.001721
        )
    
    
    def chirp(pwm_channel):
        for peep in chirp_data:
            pwm_channel.freq(peep[2])
            pwm_channel.duty_u16(peep[1])
            sleep_ms(cadence_ms * peep[0])
            # short silence
            pwm_channel.duty_u16(0)
            pwm_channel.freq(10)
            sleep_ms(cadence_ms)
    
    
    led.value(0)  # led off at start; blinks if chirping
    ### Start: pause a random amount (less than 2 s) before starting
    sleep_ms(randrange(2000))
    
    while True:
        loop_start_ms = ticks_ms()
        sleep_ms(5)  # tiny delay to stop the main loop from thrashing
        temps.append(internal_temperature(sensor_temp))
        if len(temps) > 5:
            temps = temps[1:]
        avg_temp = sum(temps) / len(temps)
        if avg_temp >= TOO_COLD:
            led.value(1)
            loop_period_ms = chirp_period_ms(avg_temp)
            chirp(pwm_out)
            led.value(0)
            loop_elapsed_ms = ticks_diff(ticks_ms(), loop_start_ms)
            sleep_ms(loop_period_ms - loop_elapsed_ms)
    

    There are a few more details in the code that I haven’t covered here:

    1. The program pauses for a short random time on starting. This is to ensure that if you power up a bunch of these at the same time, they don’t start exactly synchronized
    2. The Raspberry Pi Pico’s temperature sensor can be slightly noisy, so the chirping frequency is based on the average of (up to) the last five readings
    3. There’s no chirping below 10 °C, because Amos Dolbear said so
    4. The built-in LED also flashes if the board is chirping. It doesn’t mimic the speaker’s PWM cadence, though.

    Before I show you the next video, I need to say: no real crickets were harmed in the making of this post. I took the bucket outside (roughly -5 °C) and the “crickets” stopped chirping as they cooled down. Don’t worry, they started back up chirping again when I took them inside.

    “If You’re Cold They’re Cold, Bring Them Inside”
    (video description: a plastic box containing three USB power banks, each with USB cable leading to a Raspberry Pi Pico board. Each board has a small electromagnetic speaker attached between ground and a data pin)

  • maximal annoyance with the BBC micro:bit and MicroPython

    I just picked up a micro:bit, the little educational microprocessor board originally from the BBC. It’s a nice little unit, though like all educational resources, it’s sometimes hard to access resources as a non-edu type.

    I landed upon MicroPython, a Python language subset that runs directly on the micro:bit’s ARM chip. I rather like the Mu editor:
    To give the old microcontroller grumps something real to complain about, MicroPython includes a bunch of very high-level functions, such as a powerful music and sound module. Getting the sound out is easy: just croc-clip a speaker onto the output pads:

    (MicroPython warns against using a piezo buzzer as a speaker, but mine worked fine — loudly and supremely annoyingly — with a large piezo element. Some piezos have a fixed-frequency oscillator attached, but this simple one was great.)

    This trivial example plays the Nyan Cat theme forever, but every time it loops it gets faster. The beats variable starts at the default 120 bpm, but is increased by one every time:

    # nyan but it gets faster
    import music
    beats = 120
    while True:
        music.set_tempo(bpm=beats)
        music.play(music.NYAN)
        beats = beats + 1
    

    This starts out as merely irritating, but quite quickly becomes deeply annoying, and in mere hours become vastly vexing. I’m sure you’d only use this power for good …

  • Ⓗⓞⓦ ⓣⓞ â“‘â“” ⓐⓝⓝⓞⓨⓘⓝⓖ ⓦⓘⓣⓗ Ⓟⓔⓡⓛ ⓐⓝⓓ Ⓤⓝⓘⓒⓞⓓⓔ

    It’s been so long since I’ve programmed in Perl. Twelve years ago, it was my life, but what with the Raspberry Pi intervening, I hadn’t used it in a while. It’s been so long, in fact, that I wasn’t aware of the new language structures available since version 5.14. Perl’s Unicode support has got a lot more robust, and I’m sick of Python’s whining about codecs when processing anything other than ASCII anyway. So I thought I’d combine re-learning some modern Perl with some childish amusement.

    What I came up with was a routine to convert ASCII alphanumerics ([0-9A-Za-z]) to Unicode Enclosed Alphanumerics ([⓪-⑨Ⓐ-Ⓩⓐ-ⓩ]) for advanced lulz purposes. Ⓘ ⓣⓗⓘⓝⓚ ⓘⓣ ⓦⓞⓡⓚⓢ ⓡⓐⓣⓗⓔⓡ ⓦⓔⓛⓛ:

    #!/usr/bin/perl
    # annoying.pl - ⓑⓔ ⓐⓝⓝⓞⓨⓘⓝⓖ ⓦⓘⓣⓗ ⓤⓝⓘⓒⓞⓓⓔ
    # created by scruss on 2014-05-18
    
    use v5.14;
    # fun UTF8 tricks from http://stackoverflow.com/questions/6162484/
    use strict;
    use utf8;
    use warnings;
    use charnames qw( :full :short );
    sub annoyify;
    
    die "usage: $0 ", annoyify('string to print like this'), "\n" if ( $#ARGV < 0 );
    say annoyify( join( ' ', @ARGV ) );
    exit;
    
    # 💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩
    
    sub annoyify() {
        # convert ascii to chars in circles
        my $str = shift;
        my @out;
        foreach ( split( '', $str ) ) {
            my $c = ord($_);             # remember, can be > 127 for UTF8
            if ( $c == charnames::vianame("DIGIT ZERO") )
    	{
                # 💩💩💩 sigh; this one's real special ... 💩💩💩
                $c = charnames::vianame("CIRCLED DIGIT ZERO");
            }
            elsif ($c >= charnames::vianame("DIGIT ONE")
                && $c <= charnames::vianame("DIGIT NINE") )
            {
                # numerals, 1-9 only (grr)
                $c =
                  charnames::vianame("CIRCLED DIGIT ONE") +
                  $c -
                  charnames::vianame("DIGIT ONE");
            }
            elsif ($c >= charnames::vianame("LATIN CAPITAL LETTER A")
                && $c <= charnames::vianame("LATIN CAPITAL LETTER Z") )
            {
                # upper case
                $c =
                  charnames::vianame("CIRCLED LATIN CAPITAL LETTER A") +
                  $c -
                  charnames::vianame("LATIN CAPITAL LETTER A");
            }
            elsif ($c >= charnames::vianame("LATIN SMALL LETTER A")
                && $c <= charnames::vianame("LATIN SMALL LETTER Z") )
            {
                # lower case
                $c =
                  charnames::vianame("CIRCLED LATIN SMALL LETTER A") +
                  $c -
                  charnames::vianame("LATIN SMALL LETTER A");
            }
            else {
                # pass thru non-ascii chars
            }
            push @out, chr($c);
        }
        return join( '', @out );
    }
    

    Yes, I really did have to do that special case for ⓪; ⓪…⑨ are not contiguous like ASCII 0…9. ⓑⓞⓞ!

  • Introducing RAFTP: the Really Annoying File Transfer Protocol

    I would like to describe a new and highly impractical method of transferring data between computers. Modern networks are getting more efficient every year. This protocol aims to reverse this trend, as RAFTP features:

    1. Slow file transfers
    2. A stubborn lack of error correction
    3. The ability to irritate neighbours while ensuring inaccurate transmission through playing the data over the air using Bell 202 tones.

    doge-small-tx
    Figure 1

    Figure 1 shows a test image before it was converted into PGM format. This was then converted into an audio file using  minimodem:

    minimodem --tx -v 0.90 -f doge-small-1200.wav 1200 < doge-small-tx.pgm

    This file was then transferred to an audio player. To ensure maximal palaver, the audio player was connected to a computer via a USB audio interface and a long, minimally-shielded audio cable. The output was captured as mp3 by Audacity as this file: RAFTP-demo

    The mp3 file was then decoded back to an image:

    madplay -o wav:- RAFTP-demo.mp3 | minimodem --rx -q -f - 1200 | rawtopgm 90 120 | pnmtopng > doge-small-rx.png

    Figure 2 shows the received and decoded file:

    Figure 2
    Figure 2

  • Ever heard the term “Appropriate Use of Technology”?

    Well, this is not that: For He’s a Jolly Good Fellow [mp3], as played on this:

    — an Arduino driving a stepper motor driving a Sankyo musical box. And yes, heat-shrink tubing ‘reinforced’ with dental floss doesn’t make a very robust flexible coupling.

  • worst earworm ever

    No, not Badger Badger Badger, but The Flying Pickets’ acappella cover of Yazoo’s “Only You”. Argh.