Warhammer Case

The boy child has started to get into Warhammer. Enough to get a case! The official ones are really expensive and I’d rather save my money for a resin printer to print all the mini’s! Other options were to buy 3rd party or make one. So of course I made one.

I managed to pick up a second hand flight case from ebay for £13, local so no postage.

Then i got some foam inserts that fit from ebay. – £17

https://www.ebay.co.uk/itm/183525532229

I riveted on an eyelet to the inside of the base and the lid. This is to take the strain off the back and the hinges when the case is open. I always do this with flight cases. Helps them last a lot longer bit is not strictly necessary. Not sure on price as I had loads lying around, the string between them is just a bit of paracord.

The bottom tray is hot glued in place and the next tray sits on top. This will store around 105 miniatures.

Possible improvements

  • I could take the foam out of the lid and add in a third layer of miniatures.
  • Definitely want to add a logo, will have to consult the boy child.
  • Could possibly make a glowing logo…..

Total Cost: £30

Control Center

Project Status: Complete

I’m jealous of the boy’s Rave Cave Control Panel (see here) so with the lessons learned I’m going to build myself a more basic version, he says getting carried away with the planning already.

My basic idea is to have all of the various power switches in one rack. This is going to be a riser for my monitor at the same time. The space I have under the primary monitor is 57mm (h) x 150mm (d) x 530mm (w). The only essential measurement is the height to get the monitor for to the right height for my sitting position.

I’ve bought another 230V(ac) to 5V(dc) transformer so I should only need a single power in.

  • Each switch should be a nice chunky tear-drop toggle switch.
  • Each switch should have a changeable name plate.
  • Each switch should have an indicator LED
  • The front panel should be removable/replaceable in case I want to update the switch layout or number.
  • The top panel should be removable for ease of maintenance.

What do I want to switch?

  • Master Switch (to turn the whole box on/off)
  • AC1 (for an external power bar that will power 2 screens and the docking station)
  • AC2 (angle lamp)
  • USB1 (lamp)
  • USB2 (spare)
  • USB3 (spare)
  • USB4 (lamp)

The AC switches and master switch will need to be DPDT so one side will switch the AC and one side DC for the indicator LED.

I’m going to bash this out in wood to start with until I can find something cool looking to house it all!

Here’s version 1… The top lifts off and the front is yet to be attached as it’s going to have lots of holes drilled in it!

Here’s the front plate with holes drilled for the switches. The box ended up being so big that I’m going to use the left-hand side to hide my USB3 docking station and tidy away the clutter of cables.

Here are the switched and LED holders in place to get a feel for it. Pretty happy so far.

There wasn’t space for the names plates to be added so I think I’m just going to go for different colour LEDs (green for the master, red for AC and blue for USB).

Here’s the AC side of things wired up (except for the LEDs).

Here’s the back of the box so far, 1 input that is fused and has some filters to clean up the supply and 2 outputs.

Still haven’t wired up the USB power and sockets or added the LEDs as the 5V power supply that I’ve ordered hasn’t arrived yet. What I have done is start on a second one as I have two monitors! This one is going to be a weird ass shape as the monitors are at different angles!

I still need to cut the front panel and do a shit load of sanding.

The 5V transformer arrived and is now all wired in, along with the USB sockets. Excuse the bad photos… I got excited and it was getting late.

Switches in order:

  • Main power
  • 2x AC
  • 4x USB

Improvements

I’ve got a few ideas for things to go in here but that may be a different project.

  • Some LED controls (random geek options on a rotary switch)
  • An audio selector to switch outputs from speakers to headset
  • An audio selector to switch inputs from laptop to random
  • An amp? Possibly, if I want to stop just using my minirig

Rave Cave Control Panel

Project Status: Under Construction

My boy has a bunk-bed, the bottom half doesn’t have a bed, its boarded out and surrounded by camo net. Its also got lights in it. I want a control panel to control the following:

  • The existing lights
  • Some audio samples
  • Some video loops to playback in a porthole
  • Some addressable LEDs.

The existing lights are:

  • Fairy lights (multi-colour)
  • Laser (red and green)
  • RGB Flood (with a IR remote control)

At the moment he controls these by powering them on with a switched extension block attached to the headboard.

Existing Lights

Option 1

Make a single box that attaches to the headboard that contains all of the plugs and sockets, has one power inlet and presents only the switches in a dashboard.

Option 2

Make two boxes, one with the plugs and sockets and then a but of flexible conduit running to a much smaller box with just the switches.

Components

Sockets
https://www.toolstation.com/axiom-low-profile-unswitched-socket/p10119

Dry Boxes
https://www.toolstation.com/axiom-dry-lining-box/p78122

Update

So I have a better idea that is more flexible. The control panel will have the power and switches but will then have outlet sockets that I can connect extension leads to.

https://www.aliexpress.com/item/4000381014457.html

These outlets will be controlled by toggle switches on the control panel.

https://www.aliexpress.com/item/32800984154.html

Each outlet will be connected to a single domestic 13 Amp socket.

https://www.aliexpress.com/item/10000046026506.html

I know I need 3 already so I’l probably wire up 4, no harm in having a spare and they will be easy to wire up.

Porthole Videos

So far my ideas for the views are:

Aquarium
https://www.youtube.com/watch?v=zJ7hUvU-d2Q

Space Travel
https://www.youtube.com/watch?v=XeUP83wRhjQ
https://www.youtube.com/watch?v=nGnX6GkrOgk
https://www.youtube.com/watch?v=bZNFRIwlQxQ
https://www.youtube.com/watch?v=NtOwzU5Rpp8 (Short Loop)

Earth Orbit / ISS
https://www.youtube.com/watch?v=Xjs6fnpPWy4

Polar / Winter Landscape
https://www.youtube.com/watch?v=9NmeAQruCgs
https://www.youtube.com/watch?v=fIrfF08azwc

Desert Landscape
https://www.youtube.com/watch?v=fvRkWO5g2HE
https://www.youtube.com/watch?v=1mexsOOHBSA (Short Loop)

Nature FlyBy
https://www.youtube.com/watch?v=BHACKCNDMW8

SciFi City
https://www.youtube.com/watch?v=Uj8DYegtrHg

Autumn
https://www.youtube.com/watch?v=oOhMGdFbYvU (Short Loop)
https://www.youtube.com/watch?v=eGD-5jYR9jk (Short Loop)

Sunset
https://www.youtube.com/watch?v=A9cHouJRGsU (Short Loop)
https://www.youtube.com/watch?v=iftmIPSr39g (Short Loop)

Clouds
https://www.youtube.com/watch?v=0_jNjpVxUt0 (Short Loop)
https://www.youtube.com/watch?v=rwfqnsK2M_s (Short Loop)

Scifi Backdrop
https://www.youtube.com/watch?v=0vcQInJglsE (Short Loop)

Lake / Storm / Jetty
https://www.youtube.com/watch?v=JXRTPAQIw-Q (Short Loop)

Porthole Components

I have some old spare computer screens, I have a Pi that I’m not currently using (so-long PiBot) and I’ve tracked down some instructions that could be good….

https://www.instructables.com/id/Play-Video-With-Python-and-GPIO/
https://www.raspberrypi.org/forums/viewtopic.php?t=101359

I like the first set of instructions but need to rejig them slightly so that its a momentary button press that triggers them or a rotary switch(?).

The thing that I am definitely missing is a porthole

Porthole Build Process

So it looks as thought the loop videos are going to work best, I’ve noted which are which above but I’ll have more of a play and find out whats happening. Now I just need to find some momentary switches…. to AliExpress!

Porthole Code so Far

This gives me 5 video buttons and an exit button. Currently you have to manually launch the code from a terminal window and the exit button only returns you to the Pi desktop.

Expand the link below to see the current code or better yet go to the public GitHub repository for the latest version.

https://github.com/IceniDesign/RaveCaveControls

Video Code So Far
#import the needed libraries
import os
import sys
import time
import subprocess
import RPi.GPIO as GPIO

#Set GPIO pin format
GPIO.setmode(GPIO.BCM)

#Setup the GPIO buttons
GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP) #YELLOW
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP) #RED
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP) #WHITE
GPIO.setup(27, GPIO.IN, pull_up_down=GPIO.PUD_UP) #BLUE
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_UP) #GREEN
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP) #BLACK

#VARIABLES
movie1 = ("/home/pi/Videos/Loop_Videos/Space_u9TuAZHeziw_240p.mp4")
movie2 = ("/home/pi/Videos/Loop_Videos/Clouds_0_jNjpVxUt0_240p.mp4")
movie3 = ("/home/pi/Videos/Loop_Videos/Fish_A2WqvBVCUJQ_360p.mp4")
movie4 = ("/home/pi/Videos/Loop_Videos/Desert_1mexsOOHBSA_240p.mp4")
movie5 = ("/home/pi/Videos/Loop_Videos/Sunset_A9cHouJRGsU_240p.mp4")
Layer = 1 #this needs to be presented as a string not a variable
OMX1 = '' #Define them early so we can try and kill them even if they aren't running
OMX1_active = False
OMX2 = '' #Define them early so we can try and kill them even if they aren't running
OMX2_active = False
OMX3 = '' #Define them early so we can try and kill them even if they aren't running
OMX3_active = False
OMX4 = '' #Define them early so we can try and kill them even if they aren't running
OMX4_active = False
OMX5 = '' #Define them early so we can try and kill them even if they aren't running
OMX5_active = False

#and off we go...
os.system('killall omxplayer.bin') #kill OMX in case it is already running
#Space = subprocess.Popen(['omxplayer', '--loop', '--win', '600,100,900,400', '--layer', str(Layer), movie2],stdin=subprocess.PIPE) #Load the 1st video
OMX1_active = True
OMX1 = subprocess.Popen(['omxplayer', '--loop', '--win', '600,100,900,400', '--layer', str(Layer), movie1],stdin=subprocess.PIPE) #Load the 1st video
        
while True:
    #Read states of the inputs
    button1 = GPIO.input(17) #Yellow
    button2 = GPIO.input(18) #Red
    button3 = GPIO.input(27) #Blue
    button4 = GPIO.input(22) #Green
    button5 = GPIO.input(23) #Black
    quit_video = GPIO.input(24) #White

    #If GPIO(17) is shorted to ground
    if button1 == False: #If button1 is pressed...
        if OMX1_active == False: #And movie1 is not already running
            #Play movie1
            Layer = Layer + 1
            OMX1_active = True
            OMX1 = subprocess.Popen(['omxplayer', '--loop', '--win', '600,100,900,400', '--layer', str(Layer), movie1],stdin=subprocess.PIPE) #Load the 1st video
            time.sleep(5)
            if OMX2_active == True: #shutdown movie2 if it is playing
                OMX2.stdin.write('q')
                OMX2.stdin.flush()
                OMX2_active = False
            if OMX3_active == True: #shutdown movie3 if it is playing
                OMX3.stdin.write('q')
                OMX3.stdin.flush()
                OMX3_active = False
            if OMX4_active == True: #shutdown movie4 if it is playing
                OMX4.stdin.write('q')
                OMX4.stdin.flush()
                OMX4_active = False
            if OMX5_active == True: #shutdown movie4 if it is playing
                OMX5.stdin.write('q')
                OMX5.stdin.flush()
                OMX5_active = False

    elif button2 == False: #ElseIf button2 is pressed...
        if OMX2_active == False: #And movie1 is not already running
            #Play movie2
            Layer = Layer + 1
            OMX2_active = True
            OMX2 = subprocess.Popen(['omxplayer', '--loop', '--win', '600,100,900,400', '--layer', str(Layer), movie2],stdin=subprocess.PIPE) #Load the 1st video
            time.sleep(5)
            if OMX1_active == True: #shutdown movie1 if it is playing
                OMX1.stdin.write('q')
                OMX1.stdin.flush()
                OMX1_active = False
            if OMX3_active == True: #shutdown movie3 if it is playing
                OMX3.stdin.write('q')
                OMX3.stdin.flush()
                OMX3_active = False
            if OMX4_active == True: #shutdown movie4 if it is playing
                OMX4.stdin.write('q')
                OMX4.stdin.flush()
                OMX4_active = False
            if OMX5_active == True: #shutdown movie4 if it is playing
                OMX5.stdin.write('q')
                OMX5.stdin.flush()
                OMX5_active = False
                
    elif button3 == False: #ElseIf button2 is pressed...
        if OMX3_active == False: #And movie1 is not already running
            #Play movie2
            Layer = Layer + 1
            OMX3_active = True
            OMX3 = subprocess.Popen(['omxplayer', '--loop', '--win', '600,100,900,400', '--layer', str(Layer), movie3],stdin=subprocess.PIPE) #Load the 1st video
            time.sleep(5)
            if OMX1_active == True: #shutdown movie1 if it is playing
                OMX1.stdin.write('q')
                OMX1.stdin.flush()
                OMX1_active = False
            if OMX2_active == True: #shutdown movie3 if it is playing
                OMX2.stdin.write('q')
                OMX2.stdin.flush()
                OMX2_active = False
            if OMX4_active == True: #shutdown movie4 if it is playing
                OMX4.stdin.write('q')
                OMX4.stdin.flush()
                OMX4_active = False
            if OMX5_active == True: #shutdown movie4 if it is playing
                OMX5.stdin.write('q')
                OMX5.stdin.flush()
                OMX5_active = False
                
    elif button4 == False: #ElseIf button2 is pressed...
        if OMX4_active == False: #And movie1 is not already running
            #Play movie2
            Layer = Layer + 1
            OMX4_active = True
            OMX4 = subprocess.Popen(['omxplayer', '--loop', '--win', '600,100,900,400', '--layer', str(Layer), movie4],stdin=subprocess.PIPE) #Load the 1st video
            time.sleep(5)
            if OMX1_active == True: #shutdown movie1 if it is playing
                OMX1.stdin.write('q')
                OMX1.stdin.flush()
                OMX1_active = False
            if OMX2_active == True: #shutdown movie3 if it is playing
                OMX2.stdin.write('q')
                OMX2.stdin.flush()
                OMX2_active = False
            if OMX3_active == True: #shutdown movie4 if it is playing
                OMX3.stdin.write('q')
                OMX3.stdin.flush()
                OMX3_active = False
            if OMX5_active == True: #shutdown movie4 if it is playing
                OMX5.stdin.write('q')
                OMX5.stdin.flush()
                OMX5_active = False
                
    elif button5 == False: #ElseIf button2 is pressed...
        if OMX5_active == False: #And movie1 is not already running
            #Play movie2
            Layer = Layer + 1
            OMX5_active = True
            OMX5 = subprocess.Popen(['omxplayer', '--loop', '--win', '600,100,900,400', '--layer', str(Layer), movie5],stdin=subprocess.PIPE) #Load the 1st video
            time.sleep(5)
            if OMX1_active == True: #shutdown movie1 if it is playing
                OMX1.stdin.write('q')
                OMX1.stdin.flush()
                OMX1_active = False
            if OMX2_active == True: #shutdown movie4 if it is playing
                OMX2.stdin.write('q')
                OMX2.stdin.flush()
                OMX2_active = False
            if OMX3_active == True: #shutdown movie3 if it is playing
                OMX3.stdin.write('q')
                OMX3.stdin.flush()
                OMX3_active = False
            if OMX4_active == True: #shutdown movie4 if it is playing
                OMX4.stdin.write('q')
                OMX4.stdin.flush()
                OMX4_active = False
                
    #If GPIO(24) is shorted to ground
    if quit_video == False:
        os.system('killall omxplayer.bin')
        exit()

Porthole Code Improvements…

  • The script should fire up as the Pi loads up
  • The exit button should be a hidden button for troubleshooting
  • There should be a flag to set if the videos are full screen or window for debugging
  • There is a lot of repetitive code that could be written out especially if this can go up to 20 videos!
  • There should be a shutdown button that closes the videos and shuts down the Pi
  • The last one is a big one……. should this be a flight between destinations? As in should pressing a button play a take-off video / space video / landing video? At the moment it just loads whichever loop you select with no transition.

Porthole Draft Hardware

First I’ve soldered jumper cables and heat-shrink onto the switches. The cables are colour coded to make it easier to work out which is which when I’m looking at the other side.

Then I quickly knocked up a draft box to hold the switches while I’m doing my prototyping. I’ve made it over large so I can add additional switches.

Here’s the first draft. I should have thought this through more as it doesn’t quite fit the Pi in there as well! Oh well its only a draft and there will be a shiney box coming soon anyway.

Porthole Hardware Improvement Ideas

  • Larger slimmer case, probably based on the skeleton of a rack mount network switch (I work in IT, they are free for me!)
  • More switches
  • More lights
  • Add the Pi into the case
  • Add the unused ports as external ports to the box (power, 2x USB, Network, Audio, HDMI)

1st Round of Improvements

Now all my shiny switches are mounted in an old piece of networking hardware that was broken. I work in IT so stuff like this is easy to obtain for free but check out my scrounging post if you want some ideas on getting free stuff!
https://icenidesign.com/scrounging-and-on-the-cheap/

The twelve switches down the left-hand side don’t currently do anything but my idea is to have them control audio clips (robots and dinosaurs is the boys request!)

The holes for the switches were all cut using a stepped drill bit which are awesome!

They are fairly cheap and definitely worth the investment.

I bought a stand-off kit from ebay to mount various electronics to the inside of the box! This project is starting to look expensive but I’ve pretty much got enough parts to build 10 of them! The kit that I bought is no longer available but if you google “standoff kit” there are loads out there.

One problem I have is that I’m mounting the hardware to the bottom of the case and the switches to the top of the case. So I’ve decided to link the top of the case to the bottom of the case with a few 9-pin serial cables. i decided on 9-pin as that is a standard more likely to be of use in the future, its cheap and I can run multiple cables when needed. I could have gone for 25 pin but they are really bulky.

I’ll probably end up mounting 3 or 4 of these on the top of the case and 3 or 4 on the bottom of the case. They are really cheap!
https://www.aliexpress.com/item/32838512514.html?spm=a2g0s.9042311.0.0.4d734c4dx3t83z

My idea is to have one connector for each group of buttons (6 live + 1 GND for each set, leaves 2 spare pins, possibly for led lights).

Addressable LEDs

So the next bits I wanted to do was to also have some addressable LED lights connected with another batch of buttons on there for more controls.

I’ve picked up a few bits to play with…

https://www.aliexpress.com/item/32241249128.html?spm=a2g0s.9042311.0.0.27424c4d2OeBw9


https://www.aliexpress.com/item/32682015405.html?spm=a2g0s.9042311.0.0.27424c4d2OeBw9

Some Reading to Do

https://www.arduino.cc/en/tutorial/button

Turns out that the Arduino page has some really good tutorials.

Addressable LED Code Attempt 1

Here’s my first attempt at Arduino coding with FastLED, 6 buttons controlling a strip of RGB addressable LEDs

Expand the link below to see the current code or better yet go to the public GitHub repository for the latest version.

https://github.com/IceniDesign/RaveCaveControls

Addressable LEDs Code So Far
#include <FastLED.h>

#define buttonPin_BLACK   2
#define buttonPin_WHITE   3
#define buttonPin_RED     4
#define buttonPin_GREEN   5
#define buttonPin_BLUE    6
#define buttonPin_YELLOW  7
#define LED_PIN     12
#define NUM_LEDS    30
#define BRIGHTNESS  20
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

#define UPDATES_PER_SECOND 100

// variables will change:
int buttonState_BLACK = 0;        // variable for reading the pushbutton status
int buttonState_WHITE = 0;        // variable for reading the pushbutton status
int buttonState_RED = 0;        // variable for reading the pushbutton status
int buttonState_GREEN = 0;        // variable for reading the pushbutton status
int buttonState_BLUE = 0;        // variable for reading the pushbutton status
int buttonState_YELLOW = 0;        // variable for reading the pushbutton status

// This example shows several ways to set up and use 'palettes' of colors
// with FastLED.
//
// These compact palettes provide an easy way to re-colorize your
// animation on the fly, quickly, easily, and with low overhead.
//
// USING palettes is MUCH simpler in practice than in theory, so first just
// run this sketch, and watch the pretty lights as you then read through
// the code.  Although this sketch has eight (or more) different color schemes,
// the entire sketch compiles down to about 6.5K on AVR.
//
// FastLED provides a few pre-configured color palettes, and makes it
// extremely easy to make up your own color schemes with palettes.
//
// Some notes on the more abstract 'theory and practice' of
// FastLED compact palettes are at the bottom of this file.



CRGBPalette16 currentPalette;
TBlendType    currentBlending;

extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;


void setup() {
    delay( 3000 );                // power-up safety delay
    pinMode(buttonPin_BLACK, INPUT);    // initialize the pushbutton pin as an input:
    pinMode(buttonPin_WHITE, INPUT);    // initialize the pushbutton pin as an input:
    pinMode(buttonPin_RED, INPUT);    // initialize the pushbutton pin as an input:
    pinMode(buttonPin_GREEN, INPUT);    // initialize the pushbutton pin as an input:
    pinMode(buttonPin_BLUE, INPUT);    // initialize the pushbutton pin as an input:
    pinMode(buttonPin_YELLOW, INPUT);    // initialize the pushbutton pin as an input:
    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );
    
    currentPalette = RainbowColors_p;
    currentBlending = LINEARBLEND;
}


void loop()
{
    // read the state of the pushbutton values:
    buttonState_BLACK = digitalRead(buttonPin_BLACK);
    buttonState_WHITE = digitalRead(buttonPin_WHITE);
    buttonState_RED = digitalRead(buttonPin_RED);
    buttonState_GREEN = digitalRead(buttonPin_GREEN);
    buttonState_BLUE = digitalRead(buttonPin_BLUE);
    buttonState_YELLOW = digitalRead(buttonPin_YELLOW);

    // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
    if (buttonState_BLACK == HIGH) {
      currentPalette = PartyColors_p;           
      currentBlending = LINEARBLEND;
    
      static uint8_t startIndex = 0;
      startIndex = startIndex + 1; /* motion speed */
    
      FillLEDsFromPaletteColors( startIndex);
    
      FastLED.show();
      FastLED.delay(1000 / UPDATES_PER_SECOND);
    }
    else if (buttonState_WHITE == HIGH) {
      currentPalette = RainbowStripeColors_p;   
      currentBlending = NOBLEND;
    
      static uint8_t startIndex = 0;
      startIndex = startIndex + 1; /* motion speed */
    
      FillLEDsFromPaletteColors( startIndex);
    
      FastLED.show();
      FastLED.delay(1000 / UPDATES_PER_SECOND);
    }
    else if (buttonState_RED == HIGH) {
      SetupBlackAndRedStripedPalette();  
      currentBlending = LINEARBLEND;
    
      static uint8_t startIndex = 0;
      startIndex = startIndex + 1; /* motion speed */
    
      FillLEDsFromPaletteColors( startIndex);
    
      FastLED.show();
      FastLED.delay(1000 / UPDATES_PER_SECOND);
    }
    else if (buttonState_GREEN == HIGH) {
      SetupPurpleAndGreenPalette();           
      currentBlending = LINEARBLEND;
    
      static uint8_t startIndex = 0;
      startIndex = startIndex + 1; /* motion speed */
    
      FillLEDsFromPaletteColors( startIndex);
    
      FastLED.show();
      FastLED.delay(1000 / UPDATES_PER_SECOND);
    }
    else if (buttonState_BLUE == HIGH) {
      currentPalette = CloudColors_p;           
      currentBlending = LINEARBLEND;
    
      static uint8_t startIndex = 0;
      startIndex = startIndex + 1; /* motion speed */
    
      FillLEDsFromPaletteColors( startIndex);
    
      FastLED.show();
      FastLED.delay(1000 / UPDATES_PER_SECOND);
    }
    else if (buttonState_YELLOW == HIGH) {
      currentPalette = myRedWhiteBluePalette_p; 
      currentBlending = LINEARBLEND; 
    
      static uint8_t startIndex = 0;
      startIndex = startIndex + 1; /* motion speed */
    
      FillLEDsFromPaletteColors( startIndex);
    
      FastLED.show();
      FastLED.delay(1000 / UPDATES_PER_SECOND);
    }
}

void FillLEDsFromPaletteColors( uint8_t colorIndex)
{
    uint8_t brightness = 255;
    
    for( int i = 0; i < NUM_LEDS; i++) {
        leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending);
        colorIndex += 3;
    }
}


// There are several different palettes of colors demonstrated here.
//
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
//
// Additionally, you can manually define your own color palettes, or you can write
// code that creates color palettes on the fly.  All are shown here.

void ChangePalettePeriodically()
{
    uint8_t secondHand = (millis() / 1000) % 60;
    static uint8_t lastSecond = 99;
    
    if( lastSecond != secondHand) {
        lastSecond = secondHand;
        if( secondHand ==  0)  { currentPalette = RainbowColors_p;         currentBlending = LINEARBLEND; }
        if( secondHand == 10)  { currentPalette = RainbowStripeColors_p;   currentBlending = NOBLEND;  }
        if( secondHand == 15)  { currentPalette = RainbowStripeColors_p;   currentBlending = LINEARBLEND; }
        if( secondHand == 20)  { SetupPurpleAndGreenPalette();             currentBlending = LINEARBLEND; }
        if( secondHand == 25)  { SetupTotallyRandomPalette();              currentBlending = LINEARBLEND; }
        if( secondHand == 30)  { SetupBlackAndWhiteStripedPalette();       currentBlending = NOBLEND; }
        if( secondHand == 35)  { SetupBlackAndWhiteStripedPalette();       currentBlending = LINEARBLEND; }
        if( secondHand == 40)  { currentPalette = CloudColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 45)  { currentPalette = PartyColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 50)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND;  }
        if( secondHand == 55)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
    }
}

// This function fills the palette with totally random colors.
void SetupTotallyRandomPalette()
{
    for( int i = 0; i < 16; i++) {
        currentPalette[i] = CHSV( random8(), 255, random8());
    }
}

// This function sets up a palette of black and white stripes,
// using code.  Since the palette is effectively an array of
// sixteen CRGB colors, the various fill_* functions can be used
// to set them up.
void SetupBlackAndWhiteStripedPalette()
{
    // 'black out' all 16 palette entries...
    fill_solid( currentPalette, 16, CRGB::Black);
    // and set every fourth one to white.
    currentPalette[0] = CRGB::White;
    currentPalette[4] = CRGB::White;
    currentPalette[8] = CRGB::White;
    currentPalette[12] = CRGB::White;
    
}

// This function sets up a palette of black and red stripes,
// using code.  Since the palette is effectively an array of
// sixteen CRGB colors, the various fill_* functions can be used
// to set them up.
void SetupBlackAndRedStripedPalette()
{
    // 'black out' all 16 palette entries...
    fill_solid( currentPalette, 16, CRGB::Black);
    // and set every fourth one to white.
    currentPalette[0] = CRGB::Red;
    currentPalette[4] = CRGB::Red;
    currentPalette[8] = CRGB::Red;
    currentPalette[12] = CRGB::Red;
    
}

// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette()
{
    CRGB purple = CHSV( HUE_PURPLE, 255, 255);
    CRGB green  = CHSV( HUE_GREEN, 255, 255);
    CRGB black  = CRGB::Black;
    
    currentPalette = CRGBPalette16(
                                   green,  green,  black,  black,
                                   purple, purple, black,  black,
                                   green,  green,  black,  black,
                                   purple, purple, black,  black );
}


// This example shows how to set up a static color palette
// which is stored in PROGMEM (flash), which is almost always more
// plentiful than RAM.  A static PROGMEM palette like this
// takes up 64 bytes of flash.
const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM =
{
    CRGB::Red,
    CRGB::Gray, // 'white' is too bright compared to red and blue
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Red,
    CRGB::Gray,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Blue,
    CRGB::Black,
    CRGB::Black
};



// Additionl notes on FastLED compact palettes:
//
// Normally, in computer graphics, the palette (or "color lookup table")
// has 256 entries, each containing a specific 24-bit RGB color.  You can then
// index into the color palette using a simple 8-bit (one byte) value.
// A 256-entry color palette takes up 768 bytes of RAM, which on Arduino
// is quite possibly "too many" bytes.
//
// FastLED does offer traditional 256-element palettes, for setups that
// can afford the 768-byte cost in RAM.
//
// However, FastLED also offers a compact alternative.  FastLED offers
// palettes that store 16 distinct entries, but can be accessed AS IF
// they actually have 256 entries; this is accomplished by interpolating
// between the 16 explicit entries to create fifteen intermediate palette
// entries between each pair.
//
// So for example, if you set the first two explicit entries of a compact 
// palette to Green (0,255,0) and Blue (0,0,255), and then retrieved 
// the first sixteen entries from the virtual palette (of 256), you'd get
// Green, followed by a smooth gradient from green-to-blue, and then Blue

Hardware Tweaks

OK so my build was getting more and more complex… having the butttons on the ‘lid’ of the case and the circuits on the ‘bottom’ meant i was routing more and more connectors between the two so I could easily open the case to repair/upgrade.

I’d moved on from using DB9 connectors to using VGA connectors as you got 15 pins instead of 9 in pretty much the same form factor. Also VGA cables are cheaper than DB9 and its much easier to get shorter (0.5m) VGA cables.

Then I thought of moving most of the circuits to the lid so that I needed fewer VGA cables. I didn’t want to add everything to the lid as I would turn the top side of the lid into swiss cheese and ruin the aesthetics.

Then came another small revelation. why don’t I hang a shelf / bracket off the inside to the lid that I can turn into swiss cheese! This could be attached by 4 screws through the corners of the bracket to the lid and then mount all of the circuit boards on the bracket. This means that the only cables running from the bottom to the lid should be the power cables.

Now I need to grab some thin metal to bend into the shape of the bracket. I reckon that I can grab the side panel from the side of a scrap PC and bend it into the appropriate shape.

As always I’m jumping around all over the place so I’ve added a power light and an on-switch for the switches that will control the audio samples on the left.

At some point I missed out adding the fact that I’ve mounted the buttons for RGD LEDs, as well as now adding an off/on switch and power indicator LED.

Here’s where I am with the hardware so far.

Some of the power connectors have now arrived as well so I can start adding in the external power controls for the lighting that is already in the Rave Cave.

Fitted the power outlets to the back. I jigsawed them out… note to self buy some ear defenders!

Started wiring up the AC circuits inside. The ground is also linked to the chassis. You can also see the 10A AC to DC converter to give me 10A @ 5V. I bought this straight of Aliexpress. I wasn’t going to try and build one myself.

I linked this up to test. Before I do much more I will add an inline fuse on the live line above the Wago connectors.

From above you can see the last few things I’m going to squeeze in (apart from 5 fast blow fuses one on the main live line and one prior to each mains power switch.

The four switches for the external power are now mounted. They were going to go across the top but room inside was just too tight.

Mains power is now complete and tested.

Sliced a diffuser for the LEDs from a milk bottle!

A reflector to mount the LEDs on cut out of ply and wrapped in aluminium tape.

The two arduinos wired in for audio samples and LEDs. I’ve abandoned the bracket mounting idea as there just isn’t enough room in the case so I’ve so far got 8 ugly screw heads showing on the case with another 4 to add for the Pi (to do the video loops). I’m really enjoying making this.

LED Controls and wiring reassembled, tested and kind of bodged together. Now to make that neat and tidy and add a couple more brackets to hold the diffuser in place. I’ve cut the brackets out of some tough clear plastic (actually an old LTO5 tape case) so they show up less from the front. I’ve doubled them up and I’ve got two rows of 12 as they are fairly low density. I’ve left the rows on separate connectors so in can come back and program them independently if I want. The are linked with some Wago connectors but I’ll solder a Y connector tomorrow.

The brackets for the diffuser were first sawn and then snipped off. They could then be snipped to an appropriate size.

Here’s one of the brackets in place so you can see what I’m rambling about!

Here’s the soldered Y connector for the LED strips, tested and working. Chuffed at how neatly this came out. Each of the separate cables were soldered and heat shrunk and then additional heat shrink over the top.

Pi Video module mounted, the two arduinos are now powered through the power switches and the power indicator LEDs added (with a 470 Ohm resistor for each as I couldn’t find a 330 but they work fine and they don’t have to be bright).

AAARrrrrrrrrrrrrrrggggghhhhhh……. I’m fine.

  • The LED strips were peeling off the aluminium tape reflector.
  • The Pi power isn’t lined up and there is a switch in the way of the USB cable
  • The Pi HDMI is pointing out over the little breadboard that I’m using (don’t judge me!)

I’ve pulled out the reflector, removed the flappy LED strips with their rubbish glue and stuck them back down with some gorgeous 3M double-sided pressure tape that I had lying around!

The power supply issue I resolved by mounting the Pi on slightly taller stand-offs, the benefit of buying a kit of them is that I have a selection. I may still need to use longer but lets run with this for now and see if it works. If I make them much longer then the Pi is going to bump into the base!

The HDMI cable issue I resolved by moving the breadboard to a different location and rewiring all the connections (doh).

Next project I need to plan out my wiring better but on the plus side because I’m anal about using reusable components I could swap out different length jumper leads in seconds as oppose to dismounting and re-soldering leads on switches. Tomorrow will see some testing of all the systems and re-gluing the LED reflector (with attached LED strips) back in place.

Audio Samples from an Arduio

So here’s where I have chosen a bunch of my samples from….

Here’s a basic tutorial I’m going to follow.

https://lastminuteengineers.com/arduino-micro-sd-card-module-tutorial/

Amplification will be done by an external portable sound system (I’m going to use a mini rig) this build is complex enough already!

https://www.arduino.cc/en/Reference/SDCardNotes

https://www.arduino.cc/en/Reference/SD

At this point I’ve realised that I only have digital outs. There are options to build my own 8-bit DAC but they all look a but shoddy and I haven’t expanded to printing my own circuit boards as of yet. There are some nice shields that that use IS2 comms to output nicer audio quality but then I stumbled across some YX5300 boards that will do both the card reader and the audio DAC as well as giving me way more features than I could need.

There seem to be some good tutorials for this board, I will give them a try and update here. I’m hoping that this will allow me to use an Arduino Nano with the board instead of the Mega 2560 that I’ve got installed and then maybe reuse my now spare Mega instead of the Pi to alleviate the issue of the Pi being sensitive to losing power and corrupting its SD card.

Random Aside

I’ve been planning on having 1 action assigned to each button for both the leds and the audio samples. Why? It’s easy enough for them to have a different setting for each time the button is pressed.

LEDs (6 buttons)

  • Solid colours
  • Chase colours
  • Patterns
  • Pulsing
  • White
  • Blackout

Each button has an integer associated with it to cycle through the options, resetting at the highest to cycle back to the lowest. Swapping to pressing a different button resets the integer on the other buttons.

Audio samples (12 buttons)

This plan has grown somewhat!

ButtonPinFolderTrack
Black A3001001-Nasa-apollo11_countdown.mp3
Black A3001002-Nasa-Mercury-4_Clock-Started.mp3
Black A3001003-Nasa-houston_problem.mp3
Black B3102001-Nasa-Mercury-6_Zero-G.mp3
Black B3102002-Nasa-eagle_has_landed.mp3
Black B3102003-Nasa-small_step.mp3
Red A3203001-StarTrek-Klaxon.wav
Red B3304001-StarWars-Han_Blaster.wav
Yellow A3405001-AmenBreak.wav
Yellow B3506001-Bridge_to_captain.mp3
Yellow B3506002-Losing_power.mp3
Yellow B3506003-Blow_up_any_minute.mp3
Yellow B3506004-Can_be_repaired.mp3
Blue A3607001-Tardis.mp3
Blue B3708001-StarWars-ee_trench_run6.wav
Green A3809001-StarWars-R2D2.wav
Green B3910001-Broadsword.mp3
White A4011001-Trex.wav
White B4112001-WilhelmScream.wav

Its alive….. (the MP3 player plays MP3s)

Expand the link below to see the current code or better yet go to the public GitHub repository for the latest version.

https://github.com/IceniDesign/RaveCaveControls

MP3 Player Code So Far
//code rearranged by Javier Muñoz 10/11/2016 ask me at javimusama@hotmail.com
#include <SoftwareSerial.h>

#define ARDUINO_TX 5//should connect to TX of the Serial MP3 Player module
#define ARDUINO_RX 6//connect to RX of the module
SoftwareSerial mySerial(ARDUINO_TX, ARDUINO_RX);//init the serial protocol, tell to myserial wich pins are TX and RX

////////////////////////////////////////////////////////////////////////////////////
//all the commands needed in the datasheet(http://geekmatic.in.ua/pdf/Catalex_MP3_board.pdf)
static int8_t Send_buf[8] = {0} ;//The MP3 player undestands orders in a 8 int string
//0X7E FF 06 command 00 00 00 EF;(if command =01 next song order)
#define NEXT_SONG 0X01
#define PREV_SONG 0X02

#define CMD_PLAY_W_INDEX 0X03 //DATA IS REQUIRED (number of song)

#define VOLUME_UP_ONE 0X04
#define VOLUME_DOWN_ONE 0X05
#define CMD_SET_VOLUME 0X06//DATA IS REQUIRED (number of volume from 0 up to 30(0x1E))
#define SET_DAC 0X17
#define CMD_PLAY_WITHVOLUME 0X22 //data is needed  0x7E 06 22 00 xx yy EF;(xx volume)(yy number of song)

#define CMD_SEL_DEV 0X09 //SELECT STORAGE DEVICE, DATA IS REQUIRED
#define DEV_TF 0X02 //HELLO,IM THE DATA REQUIRED

#define SLEEP_MODE_START 0X0A
#define SLEEP_MODE_WAKEUP 0X0B

#define CMD_RESET 0X0C//CHIP RESET
#define CMD_PLAY 0X0D //RESUME PLAYBACK
#define CMD_PAUSE 0X0E //PLAYBACK IS PAUSED

#define CMD_PLAY_WITHFOLDER 0X0F//DATA IS NEEDED, 0x7E 06 0F 00 01 02 EF;(play the song with the directory \01\002xxxxxx.mp3

#define STOP_PLAY 0X16

#define PLAY_FOLDER 0X17// data is needed 0x7E 06 17 00 01 XX EF;(play the 01 folder)(value xx we dont care)

#define SET_CYCLEPLAY 0X19//data is needed 00 start; 01 close

#define SET_DAC 0X17//data is needed 00 start DAC OUTPUT;01 DAC no output
////////////////////////////////////////////////////////////////////////////////////

#define buttonPin_WHITE   2
int buttonState_WHITE = 0;        // variable for reading the pushbutton status
#define buttonPin_BLUE   3
int buttonState_BLUE = 0;        // variable for reading the pushbutton status
#define buttonPin_BLACK   4
int buttonState_BLACK = 0;        // variable for reading the pushbutton status



void setup()
{
  pinMode(buttonPin_WHITE, INPUT);    // initialize the pushbutton pin as an input:
  pinMode(buttonPin_BLUE, INPUT);    // initialize the pushbutton pin as an input:
  pinMode(buttonPin_BLACK, INPUT);    // initialize the pushbutton pin as an input:

  Serial.begin(9600);//Start our Serial coms for serial monitor in our pc
  mySerial.begin(9600);//Start our Serial coms for THE MP3
  delay(500);//Wait chip initialization is complete
  sendCommand(CMD_SEL_DEV, DEV_TF);//select the TF card
  delay(200);//wait for 200ms

}
void loop()
{
  
  buttonState_WHITE = digitalRead(buttonPin_WHITE);
  buttonState_BLUE = digitalRead(buttonPin_BLUE);
  buttonState_BLACK = digitalRead(buttonPin_BLACK);

  if (buttonState_WHITE == HIGH) {
    sendCommand(CMD_PLAY_WITHVOLUME, 0X0F01);//play the first song with volume 15 class
    delay(1000);
  }
  else if (buttonState_BLUE == HIGH) {
    sendCommand(CMD_PLAY_WITHVOLUME, 0X0F02);//play the first song with volume 15 class
    delay(1000);
  }
  else if (buttonState_BLACK == HIGH) {
    sendCommand(CMD_PLAY_WITHVOLUME, 0X0F03);//play the first song with volume 15 class
    delay(1000);
  }
}

void sendCommand(int8_t command, int16_t dat)
{
  delay(20);
  Send_buf[0] = 0x7e; //starting byte
  Send_buf[1] = 0xff; //version
  Send_buf[2] = 0x06; //the number of bytes of the command without starting byte and ending byte
  Send_buf[3] = command; //
  Send_buf[4] = 0x01;//0x00 = no feedback, 0x01 = feedback
  Send_buf[5] = (int8_t)(dat >> 8);//datah
  Send_buf[6] = (int8_t)(dat); //datal
  Send_buf[7] = 0xef; //ending byte
  for (uint8_t i = 0; i < 8; i++) //
  {
    mySerial.write(Send_buf[i]) ;//send bit to serial mp3
    Serial.print(Send_buf[i], HEX); //send bit to serial monitor in pc
  }
  Serial.println();
}

….and already I want to change some of the samples so they cycle through when the same button is pressed. If you check the table of samples above I’ve changed that to reflect this.

I’ve also changed the pin layout slightly as this is now way better and tweaked the timing from the code above. I’ve left the one above as its easier to read if you don’t want all these bells and whistles.

MP3 Player Code So Far - now with multiple samples on some buttons
//code rearranged by Javier Muñoz 10/11/2016 ask me at javimusama@hotmail.com
//additional tweaks (lots of them) by Iceni Design.

#include <SoftwareSerial.h>

#define ARDUINO_TX 14//should connect to TX of the Serial MP3 Player module
#define ARDUINO_RX 15//connect to RX of the module
SoftwareSerial mySerial(ARDUINO_TX, ARDUINO_RX);//init the serial protocol, tell to myserial wich pins are TX and RX

////////////////////////////////////////////////////////////////////////////////////
//all the commands needed in the datasheet(http://geekmatic.in.ua/pdf/Catalex_MP3_board.pdf)
static int8_t Send_buf[8] = {0} ;//The MP3 player undestands orders in a 8 int string
//0X7E FF 06 command 00 00 00 EF;(if command =01 next song order)
#define NEXT_SONG 0X01
#define PREV_SONG 0X02

#define CMD_PLAY_W_INDEX 0X03 //DATA IS REQUIRED (number of song)

#define VOLUME_UP_ONE 0X04
#define VOLUME_DOWN_ONE 0X05
#define CMD_SET_VOLUME 0X06//DATA IS REQUIRED (number of volume from 0 up to 30(0x1E))
#define SET_DAC 0X17
#define CMD_PLAY_WITHVOLUME 0X22 //data is needed  0x7E 06 22 00 xx yy EF;(xx volume)(yy number of song)

#define CMD_SEL_DEV 0X09 //SELECT STORAGE DEVICE, DATA IS REQUIRED
#define DEV_TF 0X02 //HELLO,IM THE DATA REQUIRED

#define SLEEP_MODE_START 0X0A
#define SLEEP_MODE_WAKEUP 0X0B

#define CMD_RESET 0X0C//CHIP RESET
#define CMD_PLAY 0X0D //RESUME PLAYBACK
#define CMD_PAUSE 0X0E //PLAYBACK IS PAUSED

#define CMD_PLAY_WITHFOLDER 0X0F//DATA IS NEEDED, 0x7E 06 0F 00 01 02 EF;(play the song with the directory \01\002xxxxxx.mp3

#define STOP_PLAY 0X16

#define PLAY_FOLDER 0X17// data is needed 0x7E 06 17 00 01 XX EF;(play the 01 folder)(value xx we dont care)

#define SET_CYCLEPLAY 0X19//data is needed 00 start; 01 close

#define SET_DAC 0X17//data is needed 00 start DAC OUTPUT;01 DAC no output
////////////////////////////////////////////////////////////////////////////////////

//I have two columns (A, B) of 6 rows (Black, Red, Yellow, Blue, Green, White) of buttons
//Cycle variables are needed for buttons that play multiple samples sequentially

//~~~~ COLUMN A ~~~~
#define buttonPin_BLACK_A   30
int buttonState_BLACK_A = 0;      // variable for reading the pushbutton status
int Cycle_BLACK_A = 0;            // variable current Track Number
int Cycle_BLACK_A_NEXT = 1;       // variable next Track Number
#define buttonPin_RED_A   32
int buttonState_RED_A = 0;        // variable for reading the pushbutton status
#define buttonPin_YELLOW_A   34
int buttonState_YELLOW_A = 0;     // variable for reading the pushbutton status
#define buttonPin_BLUE_A   36
int buttonState_BLUE_A = 0;       // variable for reading the pushbutton status
#define buttonPin_GREEN_A   38
int buttonState_GREEN_A = 0;      // variable for reading the pushbutton status
#define buttonPin_WHITE_A   40
int buttonState_WHITE_A = 0;      // variable for reading the pushbutton status

//~~~~ COLUMN B ~~~~
#define buttonPin_BLACK_B   31
int buttonState_BLACK_B = 0;      // variable for reading the pushbutton status
int Cycle_BLACK_B = 1;            // variable current Track Number
int Cycle_BLACK_B_NEXT = 2;       // variable next Track Number
#define buttonPin_RED_B   33
int buttonState_RED_B = 0;        // variable for reading the pushbutton status
#define buttonPin_YELLOW_B   35
int buttonState_YELLOW_B = 0;     // variable for reading the pushbutton status
int Cycle_YELLOW_B = 1;           // variable current Track Number
int Cycle_YELLOW_B_NEXT = 2;       // variable next Track Number
#define buttonPin_BLUE_B   37
int buttonState_BLUE_B = 0;       // variable for reading the pushbutton status
#define buttonPin_GREEN_B   39
int buttonState_GREEN_B = 0;      // variable for reading the pushbutton status
#define buttonPin_WHITE_B   41
int buttonState_WHITE_B = 0;      // variable for reading the pushbutton status

void setup()
{
  // initialize the pushbutton pins as an input:
  pinMode(buttonPin_BLACK_A, INPUT);
  pinMode(buttonPin_RED_A, INPUT);
  pinMode(buttonPin_YELLOW_A, INPUT);
  pinMode(buttonPin_BLUE_A, INPUT);
  pinMode(buttonPin_GREEN_A, INPUT);
  pinMode(buttonPin_WHITE_A, INPUT);

  pinMode(buttonPin_BLACK_B, INPUT);
  pinMode(buttonPin_RED_B, INPUT);
  pinMode(buttonPin_YELLOW_B, INPUT);
  pinMode(buttonPin_BLUE_B, INPUT);
  pinMode(buttonPin_GREEN_B, INPUT);
  pinMode(buttonPin_WHITE_B, INPUT);

  Serial.begin(9600);//Start our Serial coms for serial monitor in our pc
  mySerial.begin(9600);//Start our Serial coms for THE MP3
  delay(500);//Wait chip initialization is complete
  sendCommand(CMD_SEL_DEV, DEV_TF);//select the TF card
  delay(200);//wait for 200ms
  sendCommand(CMD_SET_VOLUME, 0X08); //Set volume in hex 0-30

}
void loop()
{

  buttonState_BLACK_A = digitalRead(buttonPin_BLACK_A);
  buttonState_RED_A = digitalRead(buttonPin_RED_A);
  buttonState_YELLOW_A = digitalRead(buttonPin_YELLOW_A);
  buttonState_BLUE_A = digitalRead(buttonPin_BLUE_A);
  buttonState_GREEN_A = digitalRead(buttonPin_GREEN_A);
  buttonState_WHITE_A = digitalRead(buttonPin_WHITE_A);

  buttonState_BLACK_B = digitalRead(buttonPin_BLACK_B);
  buttonState_RED_B = digitalRead(buttonPin_RED_B);
  buttonState_YELLOW_B = digitalRead(buttonPin_YELLOW_B);
  buttonState_BLUE_B = digitalRead(buttonPin_BLUE_B);
  buttonState_GREEN_B = digitalRead(buttonPin_GREEN_B);
  buttonState_WHITE_B = digitalRead(buttonPin_WHITE_B);


  if (buttonState_BLACK_A == HIGH) {
    
    Cycle_BLACK_A = Cycle_BLACK_A_NEXT;
  
    if (Cycle_BLACK_A == 1) { //if its 1 then play the first track and make the next one track 2
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0101);
      Cycle_BLACK_A_NEXT = 2;
      delay(1000);
    }
    else if (Cycle_BLACK_A == 2) {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0102);
      Cycle_BLACK_A_NEXT = 3;
      delay(1000);
    }
    else if (Cycle_BLACK_A == 3) {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0103);
      Cycle_BLACK_A_NEXT = 4;
      delay(1000);
    }
    else {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0101); //something has gone wrong so play the first track and make the next one track 2
      Cycle_BLACK_A_NEXT = 1;
      delay(1000);
    }

  }
  else if (buttonState_BLACK_B == HIGH) {
    
    Cycle_BLACK_B = Cycle_BLACK_B_NEXT;

    if (Cycle_BLACK_B == 1) { //if its 1 then play the first track and make the next one track 2
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0201);
      Cycle_BLACK_B_NEXT = 2;
      delay(1000);
    }
    else if (Cycle_BLACK_B == 2) {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0202);
      Cycle_BLACK_B_NEXT = 3;
      delay(1000);
    }
    else if (Cycle_BLACK_B == 3) {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0203);
      Cycle_BLACK_B_NEXT = 4;
      delay(1000);
    }
    else {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0201); //something has gone wrong so play the first track and make the next one track 2
      Cycle_BLACK_B_NEXT = 2;
      delay(1000);
    }
  }
  else if (buttonState_RED_A == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0301);//play the song in folder 01, named 001xxxxxx.xxx
    delay(1000);
  }
  else if (buttonState_RED_B == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0401);//play the song in folder 01, named 001xxxxxx.xxx
    delay(1000);
  }
  else if (buttonState_YELLOW_A == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0501);//play the song in folder 01, named 001xxxxxx.xxx
    delay(1000);
  }
  else if (buttonState_YELLOW_B == HIGH) {
    
    Cycle_YELLOW_B = Cycle_YELLOW_B_NEXT;
    delay(1000);

    if (Cycle_YELLOW_B == 1) { //if its 1 then play the first track and make the next one track 2
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0601);
      Cycle_YELLOW_B_NEXT = 2;
      delay(1000);
    }
    else if (Cycle_YELLOW_B == 2) {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0602);
      Cycle_YELLOW_B_NEXT = 3;
      delay(1000);
    }
    else if (Cycle_YELLOW_B == 3) {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0603);
      Cycle_YELLOW_B_NEXT = 4;
      delay(1000);
    }
    else if (Cycle_YELLOW_B == 4) {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0604);
      Cycle_YELLOW_B_NEXT = 1;
      delay(1000);
    }
    else {
      sendCommand(CMD_PLAY_WITHFOLDER, 0X0601); //something has gone wrong so play the first track and make the next one track 2
      Cycle_YELLOW_B_NEXT = 2;
      delay(1000);
    }

  }
  else if (buttonState_BLUE_A == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0701);
    delay(1000);
  }
  else if (buttonState_BLUE_B == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0801);
    delay(1000);
  }
  else if (buttonState_GREEN_A == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0901);
    delay(1000);
  }
  else if (buttonState_GREEN_B == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0A01);
    delay(1000);
  }
  else if (buttonState_WHITE_A == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0B01);
    delay(10000);
  }
  else if (buttonState_WHITE_B == HIGH) {
    sendCommand(CMD_PLAY_WITHFOLDER, 0X0C01);
    delay(1000);
  }
}

void sendCommand(int8_t command, int16_t dat)
{
  delay(20);
  Send_buf[0] = 0x7e; //starting byte
  Send_buf[1] = 0xff; //version
  Send_buf[2] = 0x06; //the number of bytes of the command without starting byte and ending byte
  Send_buf[3] = command; //
  Send_buf[4] = 0x01;//0x00 = no feedback, 0x01 = feedback
  Send_buf[5] = (int8_t)(dat >> 8);//datah
  Send_buf[6] = (int8_t)(dat); //datal
  Send_buf[7] = 0xef; //ending byte
  for (uint8_t i = 0; i < 8; i++) //
  {
    mySerial.write(Send_buf[i]) ;//send bit to serial mp3
    Serial.print(Send_buf[i], HEX); //send bit to serial monitor in pc
  }
  Serial.println();
}

LED Controls Version 2

So I’ve now got some Nano’s and didn’t need to be using all the real estate of the Mega 2560. So now I’m going to redo the code on a Nano but have it so different presses on different buttons do different things!

Still not sure ho to mount Nanos as they are timy and the mounting holes don’t fit my standoffs! So I ended up hot-glueing a yogurt pot lid to the metal surface to avoid any shorts and basically tying the nano to that…. Really I want some nice 3D printed holders that mount the Nano’s at 90 degrees with the pins sticking out sidways but this will do for now.

Check-out git-hub for all of the latest versions of my code for the various modules.

https://github.com/IceniDesign/RaveCaveControls

Things to Fix (in order of importance)

  • 3.5mm audio out socket to be mounted on the front of the box
  • The HDMI to VGA adapter is now a bit chunky to fit in the case. I might need to swap to running HDMI to the output at the back and then convert to VGA from there.
  • Sort out setting the SD card as read only to protect the Pi from powering down.
  • Try and streamline the wiring as its really tight inside.
  • Sort a decent way to mount the Nano’s
  • Look at swapping the Mega on the MP3 player for a Nano
  • Sort out the flickering power on the front LEDs

Sort out the flickering power on the front LEDs

So the flickering lights on the front were down to some cables coming loose from opening the cover and putting strain on the connections. So I’v made up a new cable giving some more slack, added strain relief so that the tension isn’t directed to where the cables join the circuit boards and added a connector so that the LED’s can be disconnected from the lid.

Things to Fix (in order of importance)

  • 3.5mm audio out socket to be mounted on the front of the box
  • The HDMI to VGA adapter is now a bit chunky to fit in the case. I might need to swap to running HDMI to the output at the back and then convert to VGA from there.
  • Sort out setting the SD card as read only to protect the Pi from powering down.
  • Try and streamline the wiring as its really tight inside.
  • Sort a decent way to mount the Nano’s
  • Look at swapping the Mega on the MP3 player for a Nano
  • Add connectors for the other cables so the lid can be removed (not really required unless I find an easy way to do it)

Mounted the 3.5mm socket for stereo audio to the front of the box and I don’t know why but it feels like its starting to pull the whole project together!

It was fairly straight forward, I just cut some heavy stiff plastic to fit behind the existing holes in the box, drilled some mounting holes and bolted the plastic onto the frame and then drilled a hole in the plastic for the 3.5mm jack. I’m going to do the same on the back for the HDMI and a USB connector for the Pi so I’ll document that process in more detail!

Here are the two connectors that I need to mount, plus my scribbled marks on what I’m going to chop out of the back plate, along with the random chunk of plastic that I’m going to use.

Note to self:
Stop scribbling on things in sharpie when you don't have any alcohol to wipe it off again!!!

The plastic ‘plate’ is much bigger than I need because if I want to add any further connectors it’ll be much easier to mount them on the plastic.

These connectors will have to be mounted really low to avoid the cables from the switches in the lid.

So it turns out I had a few 38mm EZ SpeedClic metal cutting discs with my Dremel, so a lot of sparks later I have a rough cut hole! ready to drill mounting holes to retain the plastic back-plane and then I can cut holes in the back plane to mount the connectors.

Its messy but it works! I’ll come back and clean it up once I’ve fixed the Pi!

Things Left to Fix (in order of importance)

  • Sort out setting the SD card as read only to protect the Pi from powering down.
  • Try and streamline the wiring as its really tight inside.
  • Sort a decent way to mount the Nano’s
  • Look at swapping the Mega on the MP3 player for a Nano
  • Add connectors for the other cables so the lid can be removed (not really required unless I find an easy way to do it)

Run Script at Startup

I’m so rubbish at following my lists of things to do but I have made things better! I’ve modified the .basrc file to run the script at startup…

Boot to the CLI not the desktop

To do this change the options here…

sudo raspi-config

Change the Splash Screen

Here are some details….

https://www.thedigitalpictureframe.com/customize-your-raspberry-pi-splash-screen-raspbian-stretch-april-2019-version/

But you can shortcut this and just replace the file at….

/usr/share/plymouth/themes/pix/splash.png

Logo Template

Project Status: Backlog

I have a logo… what you didn’t know? If I’m going to repeat this logo in lots of places it would be nice to have a template I can use for spray painting, possibly various different sizes

Well to be fair, I’ve never used the logo but I’ve just made some chainmail jewelry and bought some nice boxes for it to go in …I could write ‘Iceni Design’ on the boxes but as I don’t know if I’m keeping the ‘Iceni Design’ brand I’ve decided to just use my logo.

My first idea is to project this onto aluminium mark it up and jigsaw it out but now I work at a University maybe I could get a digital version of the logo and get someone to lasercut it from acrylic or something for me!

Shield

Project Status: Complete

I have a 6 year old…. we have foam swords, I now have an excuse to make some plywood shields.

https://www.pinterest.co.uk/fearpig/shield/

[fts_pinterest type=single_board_pins pinterest_name=fearpig board_id=shield pins_count=6]

I recon I can just cut a template out of ply and then mount this one some curved battens to bend it!

I decided to keep the first one simple but I’m pretty happy with the results so far.

burst

So far I’ve just jigsawed out the shape (paper template folded in half to make it symmetrical), free-handed all of the lines in pencil, gone over the pencil with sharpie and used a silver marker. If I had a belt sander this would be so much easier…. belt sander, band saw, table saw, grinder…. these are all on my Christmas list!

Next steps will be a blue background, red (or possibly yellow lion) and then i’m thinking of some rivet detailing in the silver border before adding a simple handle on the back. If it were for a grown up then I’d go for diagonal or multi-direction straps and padding but I’ll keep it simple and just do a wooden handle!

Blue poster paint and silver paint marker for the crown and teeth.

Cut and sanded the handle, red poster paint for the lion.

2nd coat of blue, rivet details on the border, attached the handle and covered/painted the screw heads, redone the line work.

Next should just be varnishing once its dried!

After a coat of Clearcoat its looking pretty good!

Improvements for next time

  • Take more care filling ans sanding the screw heads
  • Figure out a more even way to maintain the border width rather than freehand
  • Get a band saw and table sander to make life easier!!