fbpx

Build a Split Flap Display Using a Raspberry Pi and PowerShell

I love messing around with the Raspberry PI especially when I can write scripts using my favourite scripting language PowerShell and the IoT Module! This is a guide to my latest project, a split flap display. I built it to lean how to control stepper motors and to break out the 3D printer since it had been sitting unused for too long.

Checkout the end result in the video below. It has two modes, one is for counting from 0 to 999 and another which displays random three letter words every few minutes.

If you want to build one yourself then first download the character drum model from this Thingverse project and print out as many as you need. I only used three but you could add as many as you want depending on how many IO ports you can make use of on the Raspberry PI.

Dead simple split flap display by hakernia – Thingiverse

To drive the character drum you will need some stepper motors and stepper motor controllers. This character drum was designed to work with these units and worked well although a little on the slow side and a little under powered they work fine for a DIY project.

To control the stepper motors you hook up four IO pins directly to the controller input pins in1, in2, in3 and in4. You need four separate IO pins per controller.

Here I put each character drum into its own wooden frame to keep the units separate and to house each one in its own unit.

One the units were built I tested them by hooking up the motor controller pins to pins on the Raspberry Pi. I used a separate power source to power the controllers since they draw quite a bit of power which is more than the Raspberry Pi itself can handle.

Once I had everything tested I printed out some letters and numbers using my ink jet printer and glued them to the flaps. I had some issues here with clearance of the drum to the frames to had to rip them apart and make some adjustments.

To get the flaps to work properly I needed a way to hold up the flaps and stop them flapping over to easily. I made some 3d printed fingers to hold them back.

Here I used the glue gun to hold the Raspberry Pi, controllers and power supply in place.

Wrapped everything in a balsa wood case. Its starting to look good! Final step was to use some black spray paint to lay down several layers until the surface was nice and flat.

Once it was built it was time to code up a PowerShell script using the IoT module to control the Raspberry PI’s IO pin’s.

Follow this guide I made if you want to setup PowerShell to work with the Raspberry Pi.

How To Develop PowerShell Scripts For The Raspberry Pi | SlashAdmin \ Life in IT

Once the Raspberry Pi had PowerShell and the IoT module installed I ended up with this little script to control the display.

To control each stepper motor all you need to do is set four IO pins according to a set sequence. You then keep stepping through the sequence to make the motors turn. You can then slow down or speed up the motors by adding a delay between each step.

In the code I use an array to hold the sequence required to turn the motors.

$stepSequence = @(
(1, 0, 0, 0),
(1, 1, 0, 0),
(0, 1, 0, 0),
(0, 1, 1, 0),
(0, 0, 1, 0),
(0, 0, 1, 1),
(0, 0, 0, 1),
(1, 0, 0, 1)
)

to rotate a motor one revolution you can use the following code snippet

for ($i = 0; $i -lt $stepSequence.length; $i++)
{
#Display 1
Set-GpioPin -id 22 -Value $stepSequence[$i][0] #1
Set-GpioPin -id 23 -Value $stepSequence[$i][1] #2
Set-GpioPin -id 24 -Value $stepSequence[$i][2] #3
Set-GpioPin -id 25 -Value $stepSequence[$i][3] #4
}

This uses the IoT module’s cmdlet Set-GpioPin to set the four pins to the correct step sequence from the array. So the first step results in 1 0 0 0 set on pins 22, 23, 24 and 25. To make the motor turn more you send out the next sequence 1 1 0 0 again to pins 22, 23, 24 and 25 and so on.

You can study the code sample below. Just hook up stepper motor controller one to pins, 22, 23, 24 and 25 on the raspberry pi then display two to pins 26, 27, 28 and 29 and display three to pins 5, 6, 10 and 11.

One important note is that the pin numbers I reference above are set according to the WiringPI scheme. So you have to look up the corresponding pins on the Raspberry PI. This is because the IoT module can work with different hardware so not all hardware use the same pin numbering system. So when using Set-GpioPin using pin id 22 means it must be connected to pin 31 on the Raspberry Pi. Checkout the following conversion guide:

PowerShell-IoT/rpi3_pin_layout.md at master · PowerShell/PowerShell-IoT · GitHub

Feel free to use my code below to modify and build your own!

<#
    Remember pin guide: https://github.com/PowerShell/PowerShell-IoT/blob/master/docs/rpi3_pin_layout.md

    0 to 4117 steps = A to A
    4117 / 32 = 128.65 steps per character on the display

    A   0
    B   128.65
    C   257.312
    D   385.968
    E   514.624
    F   643.280
    G   771.936
    H   900.592
    I   1029.248
    J   1157.904
    K   1286.560
    L   1415.216
    M   1543.87
    N   1672.528
    O   1801.184
    P   1929.840
    Q   2058.496
    R   2187.152
    S   2315.808    
    T   2444.464
    U   2573.120
    V   2701.776
    0   2830.432
    1   2959.088
    2   3087.744
    3   3216.400
    4   3345.056
    5   3473.712
    6   3602.368
    7   3731.024
    8   3859.680
    9   3988.336

#>

Install-Module Microsoft.PowerShell.IoT
Import-Module Microsoft.PowerShell.IoT

$positions = @{}
$positions.Add('A', 0)
$positions.Add('B', 128)
$positions.Add('C', 257)
$positions.Add('D', 385)
$positions.Add('E', 514)
$positions.Add('F', 643)
$positions.Add('G', 771)
$positions.Add('H', 900)
$positions.Add('I', 1029)
$positions.Add('J', 1157)
$positions.Add('K', 1286)
$positions.Add('L', 1415)
$positions.Add('M', 1543)
$positions.Add('N', 1672)
$positions.Add('O', 1801)
$positions.Add('P', 1929)
$positions.Add('Q', 2058)
$positions.Add('R', 2187)
$positions.Add('S', 2315)   
$positions.Add('T', 2444)
$positions.Add('U', 2573)
$positions.Add('V', 2701)
$positions.Add('0', 2830)
$positions.Add('1', 2959)
$positions.Add('2', 3087)
$positions.Add('3', 3216)
$positions.Add('4', 3345)
$positions.Add('5', 3473)
$positions.Add('6', 3602)
$positions.Add('7', 3731)
$positions.Add('8', 3859)
$positions.Add('9', 3988)

$stepSequence = @(
    (1, 0, 0, 0),
    (1, 1, 0, 0),
    (0, 1, 0, 0),
    (0, 1, 1, 0),
    (0, 0, 1, 0),
    (0, 0, 1, 1),
    (0, 0, 0, 1),
    (1, 0, 0, 1)
)

$words = "IAN", "CAT", "DOG"

#MAIN CODE START-----------
Clear-Host
Write-Host "Split Flap Display Version 0.1"

[int]$display1Position = 0
[int]$display2Position = 0
[int]$display3Position = 0

$mode = 0 #0 = counting 1 = random words

#Counting mode variables
[int]$count = -1
[string]$sCount = '{0:d3}' -f $count
$stopwatch = [system.diagnostics.stopwatch]::StartNew()

#word mode variables
$lastChagneTime = Get-Date
[string]$display = "AAA"

for ($i = 0; $i -lt $stepSequence.length; $i++) {
    
    if ($mode -eq 0) {

        if ($count -ne $stopwatch.Elapsed.Minutes) {
            Write-Host "Current Elapsed Minutes:" $stopwatch.Elapsed.Minutes
            $count = $stopwatch.Elapsed.Minutes
            $display = '{0:d3}' -f $count
            Write-Host "Displaying:" $display
        }
    }
    elseif ($mode -eq 1) {

        $timeSpan = New-TimeSpan -start $lastChagneTime -end (Get-Date)

        if ($timeSpan.Minutes -gt 2) {
            $lastChagneTime = Get-Date
            $word = Get-Random -Maximum 4
            $display = $words[$word]
            
            Write-Host "Displaying word:" $display 
            Write-Host "Char:"$display[0] "Position:"$positions[$display[0].ToString()]
            Write-Host "Char:"$display[1] "Position:"$positions[$display[1].ToString()]
            Write-Host "Char:"$display[2] "Position:"$positions[$display[2].ToString()] 
        }
    }

    if ($display1Position -eq $positions[$display[0].ToString()]) {    
    }
    else {
        #Display 1
        Set-GpioPin -id 22 -Value $stepSequence[$i][0] #1
        Set-GpioPin -id 23 -Value $stepSequence[$i][1] #2
        Set-GpioPin -id 24 -Value $stepSequence[$i][2] #3
        Set-GpioPin -id 25 -Value $stepSequence[$i][3] #4 
        $display1Position++
    }
        
    if ($display2Position -eq $positions[$display[1].ToString()]) {    
    }
    else {
        #Display 2
        Set-GpioPin -id 26 -Value $stepSequence[$i][0] #1
        Set-GpioPin -id 27 -Value $stepSequence[$i][1] #2
        Set-GpioPin -id 28 -Value $stepSequence[$i][2] #3
        Set-GpioPin -id 29 -Value $stepSequence[$i][3] #4 
        $display2Position++

    }

    if ($display3Position -eq $positions[$display[2].ToString()]) {    
    }
    else {
        #Display 3
        Set-GpioPin -id 5  -Value $stepSequence[$i][0] #1
        Set-GpioPin -id 6  -Value $stepSequence[$i][1] #2
        Set-GpioPin -id 10 -Value $stepSequence[$i][2] #3
        Set-GpioPin -id 11 -Value $stepSequence[$i][3] #4 
        $display3Position++
    }

    if ($i -eq $stepSequence.length - 1) {
        $i = -1
    }

    if ($display1Position -gt 3988) {
        $display1Position = 0
    }
    if ($display2Position -gt 3988) {
        $display2Position = 0
    }
    
    if ($display3Position -gt 3988) {
        $display3Position = 0
    }  
}

Author: Ian@SlashAdmin

Share This Post On
468 ad

Submit a Comment

Your email address will not be published. Required fields are marked *