Author Archives: Phil Tucker

A Toronto based software developer, writer, musician, motorcyclist and hardware hacker, Phil Tucker is constantly putting technology to work in new and ingenious ways. He's also a contributing writer for the prominent Canadian tech blog, Sync.

If Phil's not programming, playing music, modifying a new gadget or sailing the Great Lakes then there's really no telling what he's up to. You can follow Phil on Twitter @unmaintained.

DIY Balance Tire

Here’s how you can turn an old tire into the perfect balance training device for surfing, snowboarding, skateboarding and more. It’s so simple that it hardly needs explaining, just chop a tire in half and mount a board on top.

 
The hardest part of this project will depend on your tire, some tires have internal reinforcement in the form of steel rods along the bead, steel mesh in the tread and perhaps others that I’ve not yet encountered. For this reason it’d be best to use a Sawzall, a bandsaw, or something else that cuts steel with ease. I used a combination of a rusty old wood saw, an angle grinder and some tin snips.

Mark the tire along its center and proceed to cut it, try to keep it straight as it won’t sit flush against the board or the board won’t be level if the cuts aren’t straight (more or less). Measure and cut two 6″ blocks of 2×4″ to fit inside either end of the tire, any wood will work, I used pressure treated. Place the blocks in the tire vertically, flush with the top as pictured below. These blocks will provide a mount and support for the balance board. Pre-drill holes on either side of the tire into the mount blocks, try to keep these holes, and the blocks centered in the tire. Secure each block with a hex screw and washer, the washer on the outside of the tire.

Cut the balance board to size, ensure that it overlaps the tire by at least 1″ all around. Affix the balance board to the block mounts with two 1.5″ wood screws through the board and into each of the blocks. Sand off any rough edges and have fun.

Parts

  • Tire
  • 1′ 2×4 Lumber (mounts)
  • 3/4″ Plywood or Other (board)
  • 4x 2″ Long 1/4″ Hex Head Screws (through tire to mounts)
  • 4x 5/16″ Washers (for tire mount screws)
  • 4x 1.5″ Wood Screws (board mounting screws)

 

Tenergy Lumi Bloom Table Lamp as a Ceiling Fixture

The Tenergy Lumi Bloom is a great, inexpensive, modular table lamp, here’s how to convert it to a ceiling fixture.

To accomplish this modification I designed a number of 3D printable parts which you can find on Thingiverse. One could alternately craft these parts out of wood or some other material using the 3D designs as a guide.

The table lamps themselves are great, the branches and bulbs use the same socket base so you can create your own tree-like lamp structure and change it up at any time.

This mod has the lamp running 120 volt bulbs into the house electrical rather than 12 volt bulbs via the included adapter. If you are not comfortable making this change or working with lighting electrical please refrain from undertaking this modification.

While this modification allows you to purchase multiple lamps in order to add more bulbs to one ceiling fixture please take into account the combined wattage of the bulbs that you are using to limit the number of branches and bulbs you include.

Tenergy Lumi Bloom Table Lamp
https://amzn.to/2M1LkOM

Alternate 120 Volt Candelabra Bulbs
https://amzn.to/31U5jFO

Thingiverse 3D Parts
https://www.thingiverse.com/thing:3874820

Assembly

Bulb_Socket_Spacer_Adapter.stl

This lamp uses 12 volt bulbs, the base of which are longer than 120 volt bulbs. That being the case, 120 volt candelabra-size bulbs will not screw deep enough into the sockets to make the required connection.

To solve this problem I designed a threaded spacer with a hole in the center into which I glued about 3mm of the base of a nail (all but 2mm or so of the pin cut off).

The flat of the nail sits on the center connection of the socket when the shim is screwed in and the pin of the nail is what the bulb’s center lead will sit on when the bulb is screwed in. The nail bridges the electrical connection while the spacer screws tight into the socket and prevents any shorts. I used nails labelled 1″ 2d and Krazy Glue. The nails friction fit quite well, but to be extra caution I glue them anyway. Both the cap and tip of the nail may need to be scraped or sanded after gluing to ensure a good connection.

While one of these shims will be required for each 120 volt candelabra bulb you use with this lamp, when you’re connecting a branch to a socket rather than a bulb you will have to remove the shim. Consequently when you are re-configuring the lamp you’ll end up shuffling the shims from socket to socket.

When inserting these shims, screw them in reverse a couple turns to get them level, then they should screw in properly. Don’t tighten to hard or you’ll risk cracking the shim, snug is good to make the connection.

These shims have a slot so that a flat-head screwdriver can be used to insert and remove them. **Ensure the power to the light is off before remove or inserting any bulbs, shims, or branches.*

Fixture_Spacer_Shim.stl

To use this lamp as a ceiling fixture you must remove the base plate and power adapter socket. Then you can print this shim which will brace the lamp against your ceiling and has holes 89mm apart for connecting to the electrical fixture box in your ceiling. This shim acts as a brace that allows you to tighten the fixture without fear of bowing the plastic base.

Once you’ve printed this shim and checked against your electrical box you can use the holes as guides to drill through the base of the lamp. Drill slowly, and I wouldn’t recommend a punch of any sort since it might crack the plastic.

Bolt_Cap_Base.stl
Bolt_Cap_Cover.stl

This cap and cover allow you to hide the bolts which must go through the base and the shim to connect the lamp to your ceiling electrical fixture box. Insert the bolt into the base, mount the lamp, then place the cover on the base. It should friction fit and give a nice finished look to the fixture.

Power_Adapter_Cover.stl

This small piece is to fill the opening left after you remove the 12 volt adapter socket from the base. It simply slides into place.

Printing

I print rafts with most things, these included, other than that these models are quite simple and you shouldn’t run into any issues.

Professor McBrainy’s Zany Vortex Optical Illusion Puzzle Solution

I came across this tile puzzle at a rental cottage and it frustrated most of those in attendance. Boasting “literally billions” of possible combinations I gave it a go and shortly decided swimming and canoeing was more rewarding.

The puzzle is comprised of 16 square tiles with one of 8 patterns on each of their 4 sides. To solve the puzzle one must place these tiles in a 4-by-4 grid with their edges aligned such that the patterns on each side match the patterns on the sides of the tiles adjacent, above and below.

I was curious, however, if the solution entailed some sort of offset layout, or if it was just a standard 4-by-4 edge-aligned grid as the box implied — it’s an optical illusion puzzle after all. So I took to searching online for the solution, with no luck, I again decided swimming and canoeing was more rewarding.

Upon returning home from the cottage the puzzle nagged me, so I set to writing a program to more-or-less brute force the solution, seen below, written in C#. I didn’t feel like programming routes for every possible combination so instead I wrote in some random elements to try while systematically eliminating other factors. I found an image of the tiles online and translated them to numeric representations of their patterns and rotations. After 142,594 attempts of the last iteration of my program it found a solution. I say “a solution” because I ran it again and it found a different solution, both valid. Multiple solutions runs contrary to the packaging, but oh well.

An image of the solved puzzle can be found by clicking here. Hopefully this helps others get on with their summer rentals.

You can find some of these puzzles on Amazon, though they are long out of production.

View Solution

Successful Output

Attempt #142594
[0, 0] Tile Success
[1, 0] Tile Success
[2, 0] Tile Success
[3, 0] Tile Success
[0, 1] Tile Success
[1, 1] Tile Success
[2, 1] Tile Success
[3, 1] Tile Success
[0, 2] Tile Success
[1, 2] Tile Success
[2, 2] Tile Success
[3, 2] Tile Success
[0, 3] Tile Success
Partial Success

4       9       12      10

2       0       7       14

3       6       8       15

5       _       _       _

[1, 3] Tile Success
Partial Success

4       9       12      10

2       0       7       14

3       6       8       15

5       11      _       _

[2, 3] Tile Success
Partial Success

4       9       12      10

2       0       7       14

3       6       8       15

5       11      1       _

[3, 3] Tile Success
Puzzle Success

4       9       12      10

2       0       7       14

3       6       8       15

5       11      1       13

C# Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Puzzle_Solver
{
    class Program
    {
        static int[,] puzzle = new int[16,4] {
            {5, 1, 4, 2},
            {1, 2, 7, 2},
            {4, 3, 2, 1},
            {8, 4, 4, 7},
            {2, 1, 4, 6},
            {5, 6, 6, 8},
            {7, 5, 3, 3},
            {2, 1, 2, 3},
            {2, 3, 3, 1},
            {1, 4, 6, 2},
            {3, 2, 1, 2},
            {5, 3, 1, 2},
            {2, 1, 1, 4},
            {7, 3, 2, 5},
            {3, 1, 2, 3},
            {2, 3, 1, 1},
        };

        static void Main(string[] args)
        {
            List tile_set = new List();

            for (int x = 0; x < 16; x++)
            {
                rotation[] rotations = new rotation[4]
                {
                    new rotation(puzzle[x, 0], puzzle[x, 1], puzzle[x, 2], puzzle[x, 3]),
                    new rotation(puzzle[x, 3], puzzle[x, 0], puzzle[x, 1], puzzle[x, 2]),
                    new rotation(puzzle[x, 2], puzzle[x, 3], puzzle[x, 0], puzzle[x, 1]),
                    new rotation(puzzle[x, 1], puzzle[x, 2], puzzle[x, 3], puzzle[x, 0])
                };
                tile_set.Add(new tile(x, rotations));
            }

            bool puzzle_success = false;

            tile[,] solution;
            int[,] starting_candidates = new int[4, 4];
            int attempt = 0;
            Random random = new Random();

            while (!puzzle_success)
            {
                tile_set = tile_set.OrderBy(x => random.Next()).ToList();

                int random_offsets = random.Next(16);
                for(int ran = 0; ran < random_offsets; ran++)
                {
                    starting_candidates = random.Next(16);
                }

                for (int tile_to_offset_start = 0; tile_to_offset_start < 16; tile_to_offset_start++)
                {
                    for (int offset = 0; offset < 16; offset++)
                    {
                        attempt++;
                        List current_tile_set = tile_set.ToList();

                        // reset
                        foreach (tile t in current_tile_set)
                        {
                            t.match_rotation = null;
                        }

                        solution = new tile[4, 4];
                        Console.WriteLine("Attempt #" + attempt);

                        for (int y = 0; y < 4; y++)
                        {
                            bool tile_success = false;
                            for (int x = 0; x < 4; x++)
                            {
                                tile_success = false;
                                for (int t = 0; t < current_tile_set.Count(); t++)
                                {
                                    int t_adjusted = starting_candidates[x, y] + t;
                                    if (t_adjusted >= current_tile_set.Count())
                                    {
                                        t_adjusted -= current_tile_set.Count();
                                    }

                                    tile current_tile = current_tile_set[t_adjusted];

                                    // used
                                    if (current_tile.match_rotation != null)
                                    {
                                        continue;
                                    }

                                    int random_rotation = random.Next(4);
                                    for (int r = 0; r < 4; r++)
                                    {
                                        int rotation = random_rotation + r;

                                        if(rotation > 3)
                                        {
                                            rotation -= 4;
                                        }

                                        rotation current_rotation = current_tile.rotations[rotation];

                                        // check left
                                        if (x != 0
                                            && solution[x - 1, y].match_rotation.right != current_rotation.left)
                                        {
                                            continue;
                                        }

                                        // check top
                                        if (y != 0
                                            && solution[x, y - 1].match_rotation.bottom != current_rotation.top)
                                        {
                                            continue;
                                        }

                                        // match
                                        current_tile.match_rotation = current_rotation;
                                        solution[x, y] = current_tile;
                                        tile_success = true;
                                        Console.WriteLine("[" + x + ", " + y + "] Tile Success");
                                        break;
                                    }

                                    if (tile_success)
                                    {
                                        break;
                                    }
                                }

                                if (tile_success && x == 3 && y == 3)
                                {
                                    Console.WriteLine("Puzzle Success");
                                    output_solution(solution);
                                    puzzle_success = true;
                                    break;
                                }
                                else if (tile_success && x >= 0 && y == 3)
                                {
                                    Console.WriteLine("Partial Success");
                                    output_solution(solution);
                                    continue;
                                }
                                else if (!tile_success)
                                {
                                    Console.WriteLine("[" + x + ", " + y + "] Puzzle Fail");
                                    output_solution(solution);
                                    break;
                                }
                            }

                            if (!tile_success)
                            {
                                break;
                            }
                        }

                        int offset_x = Convert.ToInt16(Math.Floor(Convert.ToDecimal(tile_to_offset_start) / 4));
                        int offset_y = tile_to_offset_start % 4;

                        starting_candidates[offset_x, offset_y] = offset;
                    }
                }
            }
        }

        public static void output_solution(tile[,] solution)
        {
            Console.WriteLine();
            for (int y = 0; y < 4; y++)
            {
                for (int x = 0; x < 4; x++)
                {
                    Console.Write(solution[x, y] == null ? "_" : Convert.ToString(solution[x, y].id));
                    Console.Write("\t");
                }
                Console.WriteLine();
                Console.WriteLine();
            }
        }
    }

    class tile
    {
        public rotation[] rotations;
        public rotation match_rotation;
        public int id;

        public tile(int id, rotation[] rotations)
        {
            this.id = id;
            this.rotations = rotations;
        }
    }

    class rotation
    {
        public int left;
        public int top;
        public int right;
        public int bottom;        

        public rotation(int left, int top, int right, int bottom)
        {
            this.left = left;
            this.top = top;
            this.right = right;
            this.bottom = bottom;
        }
    }
}

Building a Civil War Big Muff Pi on Stripboard

On a new YouTube channel, The Joy of Electronics, I build an Electro-Harmonix “Civil War” Big Muff Pi on a stripboard/veroboard PCB.

Building a $50 Klon Centaur Clone Kit

On a new YouTube channel, The Joy of Electronics, I build a Klon Centaur clone effects pedal from an inexpensive kit.