Push

 
Push.png
 

The games in the Fallout franchise are the only ones I preorder sight unseen. This has led to some occasional disappointments, but the Fallout universe is one I've immersed myself in every few years for about two decades now. I once cosplayed as a Vault Dweller (mashed up with a Stormtrooper) and walked through central London, surrounded by similarly eccentric folk.

Some of the appeal of the Fallout games is that they're ripe with dark humour. You may be wandering the post-apocalyptic wasteland, littered with irradiated skeletons only to stumble across a circle of garden gnomes apparently worshipping a bulls skull. Perhaps you turn a corner to find a teddy bear casually placed on the rim of a toilet, holding a newspaper, with a pair of reading glasses balanced neatly on its head. The scenes themselves are odd, self contained stories that are meant to make the world seem a little off-kilter. Maybe some lunatic is roaming the area, amusing themselves with these little dioramas, but the part that makes me chuckle is that lunatic is actually one of the game developers.

Perhaps the most disconcerting moment I've had in a Fallout game is with the recently released Fallout 76. While making my character, I heard a conversation between two people about a disreputable partner. Initially I thought the conversation was vocal lines from the game, but when they said the phrase “Hang on. I'm just making my character in Fallout 76.” I realised that I was listening to a player talking on their phone. The conversation took a very absurd turn, with some incredibly colourful language, and it was at that point I checked the options menu and found there was no push-to-talk feature in the game, and that all audio picked up by players microphones would be broadcast for anyone nearby to hear (whether they wanted it to or not). What an terrifying design choice.

As an aside, listening to that conversation between two unhappy people has really expanded my vernacular; unfortunately I'll never be repeating those phrases in public.

Dice

 
Dice.png
 

Playing tabletop role-play games without dice is something that happens. Dungeons and Dragons is apparently quite popular in prisons where escapism is valuable for mental well-being and dice (otherwise used for gambling) are prohibited. I've played games during car trips where rolling a die isn't possible or practical, so the adventures have been more focused on narrative than combat. I've also seen games where people write the numbers 1 through to 20 on paper and just pull them from a bag, or games where a pack of cards is used. I have a number guessing method, which I've never seen mentioned elsewhere, but assume others could or have come up with something similar.

This guessing method replaces the most common die in D&D, the twenty sided die (known as the D20). Normally, the person running the game (the Dungeon Master, or DM) would set a difficulty between 1 and 20 for a task the player is trying to perform. A 10 might be considered an easy task, where a 20 would be remarkably difficult. The player would roll the D20 and add any modifiers to their roll based on their character's abilities. A character who is particularly athletic might add 5 to any attempt to climb a wall for example. If the roll is equal to or higher than the difficulty value, the player succeeds.

Without dice, the DM sets the difficulty of the task just like before, but now subtracts that number from 21 giving a new value we will call the Difficulty Range. The smaller the Difficulty Range, the more challenging the task. The DM then secretly chooses a “random” number between 1 and 20 and adds the Difficulty Range value, retaining the original number. If the new number exceeds 20, assume that the value has gone “around-the-horn” and continue counting from 1. These two values give the band the player will attempt to guess in order to be successful in their task. We will call this band the Target Band. Lastly, the player openly picks a number between 1 and 20, creating their own range by adding their character's ability modifier. We will call this the Player's Range. If the Player's Range intersects the Target Band, they are successful.

This system does present both DM and player with a little bit more mental gymnastics compared to simply rolling dice, but when no dice are available, the game may continue.

Dream

 
Dream.png
 

I had a dream that I had travelled back in time and wound up in a tiny, non-descript bar populated with unremarkable people without any concerns about giving contextual clues based on their dress, hair styles or otherwise. The bar itself was void of newspapers, posters, vending machines, branded taps or bottles and of course, this being my dream, I knew that I needed to identify the year I was in without letting on I was a time traveller. So what do you talk to the patrons about?

“Hey, how about that president huh?”

“We don’t talk politics since Kennedy.”

Well, we’re past 1960. It’s a little unfair that I wasn’t giving myself more information for what I believe is a top tier time traveller question but so be it.

“Fair enough, you folks interested in the space program?”

“Lost interest after the landing.”

Why would that be a reasonable second conversation thread to start? The president question was gold, but this was just silly. My unconscious brain should really be better than that, for one thing, I only really know that NASA was founded in the 1940’s, landed on the Moon in 1969, Pathfinder landed on Mars in 1997 and then anything modern is all SpaceX. Good enough I suppose, I guess it’s some time past 1970.

“OK friend, tell me about that Apple company huh.”

At which point I woke up. No one was sitting at the bar on their phone, so perhaps that wasn’t the smartest question to ask. But in waking retrospect, I’m fairly happy with my choice of questions given the ridiculous parameters my subconscious mind presented me and the sullen, unhelpful chap I was talking to. I can’t help but wonder though, which is less likely, time travel or finding a bar that didn’t have someone who wanted to express their political opinion.

Heater

 
Heater.png
 

Running outside can be enjoyable. I haven’t reached that point yet and going out for my first 0°C jog didn’t really help. Apart from wearing short running socks and getting cold shins, it didn’t half feel like my lungs were suffering from the cold air. Of course, I understand that a person will suffer from frostbite long before their lungs would ever actually freeze, but it sure doesn’t feel like that when you’re out there.

Longer socks seem like a suitable solution for the whole shin situation but heating up the air you breathe in without restricting airflow is a little trickier. Here’s my back of the napkin design idea; modify a personal cooling system (one with a backpack, vest and pump setup) to have a finned heatsink over a runner’s mouth, perhaps held in place with a system like that of a one-person band harmonica frame. I’m picturing Dick Van Dyke in Mary Poppins mixed with Tom Hardy from the Dark Knight Rises.

Instead of circulating ice-cooled water around the system, the pump would take water heated by the runner’s body temperature across the face grill, warming the air the runner breathes in. The practical restrictions and issues from the system would obviously outweigh any possible benefit. But what’s life without whimsy.

Countdown

 
Countdown.png
 

My last project presented a problem; trying to find a simple solution for an Arduino countdown timer that uses multiple chained LED matrix displays. Searching the Internet yielded no helpful results, so I ended up creating my own.

My first attempt was to create an array of three hundred characters (“05:00”, “04:59”, “04:58”, etc) and increment the pointer in the array every second. I didn't realise that this array would greatly exceed the memory on the Arduino. Next I tried setting up zones for the four displays I was using and push the values, as integers, on each one (0 for the first display, 5 for the second, 0 for the third and 0 again for the fourth). The libraries I found only accepted characters, not integers.

I toyed with the idea of creating a custom font, but that was going to take a long time. Instead I wrote the code below. It's a combination of the first two ideas, but instead of using an array of three hundred characters, it has four arrays of either six or ten characters (to represent the tens value and unit value for minutes and seconds) and has each digit mapped to a display.

#include <MD_Parola.h>
#include <SPI.h>

#define HARDWARE_TYPE MD_MAX72XX::FC16_HW  // This is the hardware setting that works for the MAX7219 8x32 LED matrix
#define CLK_PIN   13                       // LED Matrix CLK pin to Arduino 13
#define DATA_PIN  11                       // LED Matrix DIN pin to Arduino 11
#define CS_PIN    10                       // LED Matrix CS  pin to Arduino 10

uint8_t frameDelay = 25;  // Sets the frame delay for the displays to 25ms (default value)

MD_Parola P = MD_Parola(HARDWARE_TYPE, CS_PIN, 4);  // The "4" here is the number of displays connected

char* Digit0[] = {"5", "4", "3", "2", "1", "0"};                                // Values for the left most display (i.e. the tens of minutes)   - X0:00
char* Digit1[] = {"9:", "8:", "7:", "6:", "5:", "4:", "3:", "2:", "1:", "0:"};  // Values for the second display (i.e. the units of minutes)     - 0X:00
char* Digit2[] = {"5", "4", "3", "2", "1", "0"};                                // Values for the third display (i.e. the tens of seconds)       - 00:X0
char* Digit3[] = {"9", "8", "7", "6", "5", "4", "3", "2", "1", "0"};            // Values for the right most display (i.e. the units of seconds) - 00:0X

int Pointer0 = 6;     // Pointer for the tens of minute array - Set to postition six in the array for the example - 0
int Pointer1 = 5;     // Pointer for the unit of minute array - Set to position five in the array for the example - 5
int Pointer2 = 6;     // Pointer for the tens of second array - Set to position six in the array for the example  - 0
int Pointer3 = 10;    // Pointer for the unit of second array - Set to position ten in the array for the example  - 0

int Count = 0;    // Counter for the number of increments in the timer (i.e. the number of seconds passed)
int Timer = 300;  // Sets the timer to five minutes

long LastTime = 0;  // For use with the millis function

// ---------------------------------------- Setup ----------------------------------------
void setup()
{
  P.begin(4);           // Starts the display
  P.setZone(0, 0, 0);   // Assigns the zone number, first display in the zone, and last display in the zone
  P.setZone(1, 1, 1);
  P.setZone(2, 2, 2);
  P.setZone(3, 3, 3);
  P.setIntensity(0);    // Sets the display brightness

  LastTime = millis();  // Once the setup has completed, set the time reference
}

// -------------------------------------- Main Loop --------------------------------------
void loop()
{
  if(Count == Timer)  // If the counter has finished
  {
    P.setZone(0, 0, 3); // Set the display to act as one zone
    P.displayText("STOP", PA_CENTER, 0, 0, PA_PRINT, PA_NO_EFFECT);  // Display the word "STOP"
    P.displayAnimate();
  }
  else  // If the counter hasn't finished
  {
    P.displayZoneText(3, Digit0[Pointer0], PA_CENTER, 0, 0, PA_PRINT);  // Display the time remaining
    P.displayZoneText(2, Digit1[Pointer1], PA_CENTER, 0, 0, PA_PRINT);
    P.displayZoneText(1, Digit2[Pointer2], PA_CENTER, 0, 0, PA_PRINT);
    P.displayZoneText(0, Digit3[Pointer3], PA_CENTER, 0, 0, PA_PRINT);
    P.displayAnimate();
    if(millis() - LastTime >= 1000)  // If a second has passed since the last update, increment the counter - Be careful here if you run code that takes more than a second to perform
    {
      Pointer3 ++;
      Count ++;
      LastTime = millis();
    }
    if(Pointer3 == 10)  // In this section, if any of the arrays reaches the last value, set the pointer back to the first value and increment the array.  For example, if the countdown is at 01:50, instead of having the 0 become -1, set it to 9, and set the tens to 4.
    {
      Pointer3 = 0;
      Pointer2 ++;
      if(Pointer2 == 6)
      {
        Pointer2 = 0;
        Pointer1 ++;
        if(Pointer1 == 10)
        {
          Pointer1 = 0;
          Pointer0 ++;
        }
      }
    }
  }
}

I don't assume this is a common problem, but if it can help someone, all the better.

Box

 
LockBlue.png
 

Further to last weeks post, I had to overcome a number of small hurdles with the Lock Box. The biggest challenge was having not programmed for quite some time. The last project of mine that required coding was for a “reverse geo-chache box”. The idea was simple, bring a locked box (there's a pattern forming here) to a location and the lock will release. The display on the box would show the distance to the location and it was up to the user to triangulate the destination. Something about carrying around a box of wires with a big red button on it through a large city put me off that type of project for a while.

Anyway, my first version of the code was far too inefficient to use. It worked and would never be seen by anyone, but the amount of repeated functions was too much to bear. The current release version on the other hand is much cleaner. It's still not the most efficient, but it is much easier to read and work with.

Box.jpg

I did make a few mistakes along the way which should have been obvious in hind sight. The FET used to switch on the lock solenoid didn't have a suitably high current rating and blew after a few uses. Similarly, the two vibration motors are just too strong for the application. On a hard surface, the Lock Box has a tendency of slowly trying to slide itself off the edge if given half the chance.

All that being said, the project delivers on what I set out to do with it, and it's always fun to manipulate mechanisms through unconventional electronic means.

Screen.png

One final thought; if I were to make an updated version of the Lock Box, a larger display would be a must. You can hardly tell when the dinky padlocks are open on the current one.

Lock

 
Lock.png
 

After a recent, and disappointing, trip to an escape room, I set myself the challenge of creating a unique puzzle. Despite completing over a dozen escape rooms, I've not once found a puzzle that relied on “feel”. So, inspired by the tactile art of lock picking and safe cracking I made this puzzle box.

This was an interesting project that I'd probably make a number of changes to if I revisited it. For now though, I'm going to present it to friends and see how they approach solving it.