#4893498
I have to say I wish I would have found this site before I started this journey. My son has decided that he wants to be a ghostbuster for halloween and have a ghostbusters birthday. His birthday is Nov 1 so it works out well. I found a number of plans on Thingiverse for proton packs, traps, and PKE Meters and decided I'd take a crack at one of them. I originally thought the PKE Meter would be the easiest so started with that. I now think I was wrong as it was difficult to get the electronics as small as I needed it. About a month later I've completed it and it looks like this:



Image

It's based off this model on Thingiverse I scaled it up to 110%, removed a few buttons to make it easier to use for my son, and created a new battery holder for the 4 AAA's that power it. I decided on an Arduino nano as the brains with a cheap LCD for display. Again, not going for screen accurate but something that will keep a 6-7 year old entertained. I did program in the Ghostbusters 2 LED pattern for the wings.

Image

The big trick to all of this was getting the electronics to fit in such a small place. I build my own PCB from OshPark for the LED driver board/5v rail to power everything. This worked out pretty good.

Image

Image

Image

it took me about a month from start to finish to build this. I'm really pleased with how it came out. All told it cost me about $50 for materials and parts to build it.

Now I'm starting in on a proton pack for him. Sure hope I can get it all done by halloween
Last edited by CountDeMonet on May 15th, 2017, 4:54 pm, edited 1 time in total.
#4893541
Thanks :) I was originally going to use LED's like most other builds I have seen but when I saw the little LCD was less than $10 I thought I would give it a try. The one I bought is not in stock anymore but this one is basically the same thing

https://www.amazon.com/LANMU-Serial-128 ... B01G6SAWNY

Now that my son has used it a bunch I'm thinking of changing how the buttons work. Instead a press and hold I might make them a toggle.
#4893554
I might as well share the code for all of this. I don't have any full diagrams of everything but it's not that complex. I have zipped everything up including my Eagle board/schematic files if you wanted to order from oshpark or modify my boards. I have some extra 5v outputs on the rail and an extra LED spot. It also has an extra separate input with a capacitor. I was originally going to run the servo off the 5v from arduino but decided things would be more stable to run from the buck converter and the boards were already in fab when I decided to do that.

It's been a fun project. Now I'm starting in on the pack using a pair of arduino nano's and an Adafruit Audio FX Sound Board

A zip file with the 3D model STL files for printing, eagle files for the pcb, and the arduino code

The original model comes from here http://www.thingiverse.com/thing:700251 and is under the creative commons license
https://creativecommons.org/licenses/by-sa/3.0/

As far as hardware goes it uses:


The wiring is not so hard. From the battery pack 1 power/ground to the arduino vin/gnd pins and 1 power/ground to the buck converter. The converter is then adjusted for a 5v output and that goes to the power/ground of the servo. The full pin out from the arduino looks like this:

Code: Select allvin/gnd - to power
5v/gnd - to board from oshpark
A4 - SDA on LCD Display
A5 - SLC on LCD Display
D3 - Button 1 +
D4 - Button 2 +
D5 - Buzzer +
D6 - LED 1  (A7 on OshPark board)
D7 - LED 2  (A6 on OshPark board)
D8 - LED 3  (A5 on OshPark board)
D9 - LED 4  (A4 on OshPark board)
D10 - LED 5 (A3 on OshPark board)
D11 - LED 6 (A2 on OshPark board)
D12 - LED 7 (A1 on OshPark board)
D13 - Servo Signal

OshPark Board
P1 - 5v + on LCD Display
G - Gnd on LCD Display
G - Gnd on Buzzer
G - Shared ground on button board
G - Shared ground on LED wings

For the LED's I used 1 output from 1-7 on the board from OshPark to each wing.
Yes I am using one resistor for 2 LED's.
The current in this setup is less than 10ma so they will be fine


And here is the arduino code.
Code: Select all#include <Servo.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

Servo SERVO1;

int LEDNum = 0; // current LED that is lit
unsigned long previousMillis;   // will store last time LED was updated

const int LED1 = 12;
const int LED2 = 11;
const int LED3 = 10;
const int LED4 = 9;
const int LED5 = 8;
const int LED6 = 7;
const int LED7 = 6;
const int BUZZER = 5;
const int BUTTON1 = 3;
const int BUTTON2 = 4;

void setup() {
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  pinMode(LED7, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  pinMode(BUTTON1, INPUT);
  pinMode(BUTTON2, INPUT);

  digitalWrite(BUTTON1, HIGH);
  digitalWrite(BUTTON2, HIGH);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  delay(1000);

  // Clear the buffer.
  display.clearDisplay();

  SERVO1.attach(13);
  SERVO1.write(90);
}

void loop() {
  int convertedVal = 0;
  if (digitalRead(BUTTON1) == false) {
     convertedVal = 40; 
  }else if(digitalRead(BUTTON2) == false) {
    convertedVal = 90;
  }
 
  // do the led stuff
  LEDLoop(convertedVal);

  // do the servo stuff
  ServoLoop(convertedVal);

  // delay in between reads for stability
  delay(1);
}

int prevB = 0;
void drawDisplay(int level, int bar) {
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(29, 5);
  display.print("GHOSTBUSTERS");

  int b1 = random(prevB, bar);
  int b2 = random(prevB, bar);
  int b3 = random(prevB, bar);
  int b4 = random(prevB, bar);
  int b5 = random(prevB/2, bar/2);
  int b6 = random(prevB/2, bar/2);
  prevB = bar;

  display.fillRect(2, display.height() - (5 + b1), 5, b1, WHITE);
  display.fillRect(10, display.height() - (5 + b2), 5, b2, WHITE);
  display.fillRect(18, display.height() - (5 + b5), 5, b5, WHITE);
  display.fillRect(display.width() - 23, display.height() - (5 + b6), 5, b6, WHITE);
  display.fillRect(display.width() - 15, display.height() - (5 + b4), 5, b4, WHITE);
  display.fillRect(display.width() - 7, display.height() - (5 + b3), 5, b3, WHITE);
 
  display.drawCircle(display.width() / 2, display.height() / 2 + 7, level, WHITE);
 
  display.display();
}

void clearLoop() {
  display.clearDisplay();
  prevB = 0;
}

void LEDLoop(int convertedVal) {
  int ledSpeed = map(convertedVal, 0, 100, 500, 20);

  // check to see if it's time to change the state of the LED
  unsigned long currentMillis = millis();

  if ((currentMillis - previousMillis >= ledSpeed))
  {
    previousMillis = millis();

    if ( LEDNum == 0 ) {
      TriggerBuzzer();
      clearLoop();
      digitalWrite(LED3, true);
      LEDNum = 1;
      drawDisplay(21, 5);
    } else if ( LEDNum == 1 ) {
      TriggerBuzzer();
      digitalWrite(LED3, false);
      digitalWrite(LED1, true);
      LEDNum = 2;
      drawDisplay(18, 20);
    } else if ( LEDNum == 2 ) {
      TriggerBuzzer();
      digitalWrite(LED1, false);
      digitalWrite(LED6, true);
      LEDNum = 3;
      drawDisplay(15, 30);
    } else if ( LEDNum == 3 ) {
      TriggerBuzzer();
      digitalWrite(LED6, false);
      digitalWrite(LED4, true);
      LEDNum = 4;
      drawDisplay(12, 45);
    } else if ( LEDNum == 4 ) {
      TriggerBuzzer();
      digitalWrite(LED4, false);
      digitalWrite(LED7, true);
      LEDNum = 5;
      drawDisplay(9, 50);
    } else if ( LEDNum == 5 ) {
      TriggerBuzzer();
      digitalWrite(LED7, false);
      digitalWrite(LED5, true);
      LEDNum = 6;
      drawDisplay(6, 55);
    } else if ( LEDNum == 6 ) {
      TriggerBuzzer();
      digitalWrite(LED5, false);
      digitalWrite(LED2, true);
      LEDNum = 7;
      drawDisplay(3, 65);
    }else if ( LEDNum == 7 ) {
      TriggerBuzzer();
      clearLoop();
      digitalWrite(LED2, false);
      digitalWrite(LED3, true);
      LEDNum = 1;
      drawDisplay(21, 5);
    }
  }
}

void TriggerBuzzer() {
  tone(BUZZER, 2000); // Send 2KHz sound signal...
  delay(20);        // ...for 20 msec
  noTone(BUZZER);
}

void ServoLoop(int convertedVal) {
  int servoVal = map(convertedVal, 0, 100, 110, 40);
  SERVO1.write(servoVal);
}
grogking liked this
#4893894
I changed the code to toggle each state instead of requiring the button be held down. I found this is easier for my son to use. I now have everything in github here:

https://github.com/CountDeMonet/Arduino_PKE_Meter

The current code:
Code: Select all#include <Servo.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

Servo SERVO1;

int LEDNum = 0; // current LED that is lit
unsigned long previousMillis;   // will store last time LED was updated

const int LED1 = 12;
const int LED2 = 11;
const int LED3 = 10;
const int LED4 = 9;
const int LED5 = 8;
const int LED6 = 7;
const int LED7 = 6;
const int BUZZER = 5;
const int BUTTON1 = 3;
const int BUTTON2 = 4;

// know thy button state
bool medium_state = false;
bool high_state = false;
bool button1_down = false;
bool button2_down = false;

void setup() { 
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  pinMode(LED5, OUTPUT);
  pinMode(LED6, OUTPUT);
  pinMode(LED7, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  pinMode(BUTTON1, INPUT);
  pinMode(BUTTON2, INPUT);

  digitalWrite(BUTTON1, HIGH);
  digitalWrite(BUTTON2, HIGH);

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.display();
  delay(500);

  // Clear the buffer.
  display.clearDisplay();

  SERVO1.attach(13);
  SERVO1.write(90);
}

// current display val
int currentVal = 0;
void loop() {
  int button1 = digitalRead(BUTTON1);
  int button2 = digitalRead(BUTTON2);
 
  if( button1 == LOW && button1_down == false ){
        button1_down = true;
     
      if ( medium_state == true) {
        medium_state = false;
        high_state = false;
        currentVal = 0; 
      }else {
           medium_state = true;
           high_state = false;
           currentVal = 40; 
        }
  } else {
     if (button1 == HIGH && button1_down == true ){
        button1_down = false;
     }
  }
 
  if( button2 == LOW && button2_down == false ){
    button2_down = true;
   
    if(high_state == true) {
      medium_state = false;
      high_state = false;
      currentVal = 0;
    }else {
      medium_state = false;
      high_state = true;
      currentVal = 90;
    }
  }else{
    if (button2 == HIGH && button2_down == true ){
      button2_down = false;
    }
  }
 .z 
  // do the led stuff
  LEDLoop(currentVal);

  // do the servo stuff
  ServoLoop(currentVal);

  // delay in between reads for stability
  delay(1);
}

int prevB = 0;
void drawDisplay(int level, int bar) {
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(29, 5);
  display.print("GHOSTBUSTERS");

  int b1 = random(prevB, bar);
  int b2 = random(prevB, bar);
  int b3 = random(prevB, bar);
  int b4 = random(prevB, bar);
  int b5 = random(prevB/2, bar/2);
  int b6 = random(prevB/2, bar/2);
  prevB = bar;

  display.fillRect(2, display.height() - (5 + b1), 5, b1, WHITE);
  display.fillRect(10, display.height() - (5 + b2), 5, b2, WHITE);
  display.fillRect(18, display.height() - (5 + b5), 5, b5, WHITE);
  display.fillRect(display.width() - 23, display.height() - (5 + b6), 5, b6, WHITE);
  display.fillRect(display.width() - 15, display.height() - (5 + b4), 5, b4, WHITE);
  display.fillRect(display.width() - 7, display.height() - (5 + b3), 5, b3, WHITE);
 
  display.drawCircle(display.width() / 2, display.height() / 2 + 7, level, WHITE);
 
  display.display();
}

void clearLoop() {
  display.clearDisplay();
  prevB = 0;
}

void LEDLoop(int convertedVal) {
  int ledSpeed = map(convertedVal, 0, 100, 500, 20);

  // check to see if it's time to change the state of the LED
  unsigned long currentMillis = millis();

  if ((currentMillis - previousMillis >= ledSpeed))
  {
    previousMillis = millis();

    if ( LEDNum == 0 ) {
      TriggerBuzzer();
      clearLoop();
      digitalWrite(LED3, true);
      LEDNum = 1;
      drawDisplay(21, 5);
    } else if ( LEDNum == 1 ) {
      TriggerBuzzer();
      digitalWrite(LED3, false);
      digitalWrite(LED1, true);
      LEDNum = 2;
      drawDisplay(18, 20);
    } else if ( LEDNum == 2 ) {
      TriggerBuzzer();
      digitalWrite(LED1, false);
      digitalWrite(LED6, true);
      LEDNum = 3;
      drawDisplay(15, 30);
    } else if ( LEDNum == 3 ) {
      TriggerBuzzer();
      digitalWrite(LED6, false);
      digitalWrite(LED4, true);
      LEDNum = 4;
      drawDisplay(12, 45);
    } else if ( LEDNum == 4 ) {
      TriggerBuzzer();
      digitalWrite(LED4, false);
      digitalWrite(LED7, true);
      LEDNum = 5;
      drawDisplay(9, 50);
    } else if ( LEDNum == 5 ) {
      TriggerBuzzer();
      digitalWrite(LED7, false);
      digitalWrite(LED5, true);
      LEDNum = 6;
      drawDisplay(6, 55);
    } else if ( LEDNum == 6 ) {
      TriggerBuzzer();
      digitalWrite(LED5, false);
      digitalWrite(LED2, true);
      LEDNum = 7;
      drawDisplay(3, 65);
    }else if ( LEDNum == 7 ) {
      TriggerBuzzer();
      clearLoop();
      digitalWrite(LED2, false);
      digitalWrite(LED3, true);
      LEDNum = 1;
      drawDisplay(21, 5);
    }
  }
}

void TriggerBuzzer() {
  tone(BUZZER, 2000); // Send 2KHz sound signal...
  delay(20);        // ...for 20 msec
  noTone(BUZZER);
}

void ServoLoop(int convertedVal) {
  int servoVal = map(convertedVal, 0, 100, 110, 40);
  SERVO1.write(servoVal);
}

grogking liked this

The yellow slime as pink slime lite thing is also […]

Congrats on solving the mystery! I'm in a similar […]

Ghostbusters 2 Help

While we're at it, is there a version of Ghostbus[…]

Majorly awesome! I need to go find those sound cli[…]