Ghost Busters Ghost Trap |
Op deze pagina kun je alle informatie vinden over de bouw van mijn Ghost Busters Ghost Trap
Downloads en links
Link naar mijn tinkercad ontwerp.Download mijn CAD bestanden.
Download mijn Arduino Sketch (voor arduino Nano).
Download mijn geluidseffecten
Onderdelen
HoutIk heb hout gebruikt wat ik nog had liggen.
- 12mm multiplex
- 5mm multiplex - 6mm mdf
- 4mm mdf
Aluminium
Voor het handvat gebruikte ik stukjes alluminium uit de afvalbak op het werk.
Je zou deze onderdelen ook prima uit hout kunnen maken of 3d printen.
De afmetingen zijn (bij mij). 19mmx19mm voor het vierkante deel, 20mm voor het ronde handvat.
De aluminium plaatjes voor de zijkanten en de voorkant kocht ik bij www.aluminiumopmaat.nl.
De plaatjes zijn 1.5mm dik. Ik gebruikte geanodiseerde plaat en geslepen plaat (RVS look)
Verf en lijm
Grondverf van Action
Spuitbussen zwart, geel en zilver
Ik gebruikt de volgende merken en kleuren: Spraytone Hoogglans Geel, Spraytone Zijdeglans Zwart, Hammerhite metaalverf zilver.
De zilvere verf is alleen voor het koelblokje op de zijkant. Als je dat zou printen in een grijze kleur zou dat er volgens mij ook prima uitzien.
Ik gebruikte Houtlijm (patex van Action) en 5 minuten epoxylijm van bizon.
3d geprinte onderdelen
Een aantal onderdelen zijn geprint, zoals het koelblok plaatje (vector plate), de servo armpjes, de kabelgoot en een paar knopjes.
Open en kopieer het tinkercad ontwerp om die dingen te downloaden.
Arduino Nano
Dit is een oude bekende.Deze moet je altijd in huis hebben.
Klik op het plaatje voor een link naar Tinytronics
Sound board
Voor de geluidseffecten gebruik ik deze kleine MP3 speler met ingebouwde versterker.
Pas op, de opslagcapaciteit is beperkt maar groot genoeg voor dit project:
Klik op het plaatje voor een link naar Tinytronics
luidspreker
Klik op het plaatje voor een link naar Tinytronics
OLED Display
Dit is een OLED display van 128x32 pixels (erg klein dus). De aansturing gaat via I2C.
Ze zijn in meerdere kleuren te krijgen. Ik heb gekozen voor GEEL
Ik kocht dit display op AliExpress.
Accu
Ik kocht deze accu op AliExpress, het model is 104050. Het is een 3.7Volt LI-PO accu.
Accu Management en boost converter
De accu werkt op 3.7 volt maar de rest van de schakeling werkt op 5 volt. Ik heb dus een boost converter nodig om de 3.7 volt van de batterij om te vormen tot 5 volt.
Dit printje maakt het ook mogelijk om een externe voeding aan te sluiten om de batterij op te laden.
Zoektermen op AliExpress : "3.7 to 5v charge discharge"
Servos
Ik gebruik SG90 servos. In totaal 2 stuks. Het plaatje is weer een link naar Tinytronics
Neopixel LED rings
Dit zijn de Neopixel LED rings die ik gebruikte (4 stuks):
Klik op het plaatje voor een link naar de winkel
Schakelaar, potmeter en lampjes
De schakelaar is een standard toggle switch - MTS-102
Er zit één potmeter in de ghost trap, ik gebruikte deze.
De potmeter heeft een waarde van 10Kohm.
Het is lastig om een passend lampje te vinden op 5 volt.
Ik kocht dit lampje op AliExpress. De omschrijving is :"7mm plastic Indicator lights"
Dit lampje kun je bestellen voor een spanning van 12 volt, 24 volt of 230 volt; Maar niet voor 5 volt. Ik heb het lampje dus gesloopt en er een LED ingebouwd. Ze verkopen dit lampje ook bij Baco army goods in IJmuiden (een bezoek waard).
Wieltjes
De wieltjes zijn POM kogellager rollers, deze worden gebruikt in sommige 3d printers.
Oplader en spoel
Deze oplader kocht ik bij kruidvat, het is een usb-c qi lader.
Om draadloos laden mogelijk te maken heb ik deze spoel (met printje) gekocht bij AliExpress.
Het schema
Hier is mijn schema. Klik op het plaatje voor een grotere versieTest Programma's
In de videoserie test ik verschillende onderdelen, hier kun je die testprogramma's terug vinden.Servo Test
In de tweede video in deze reeks liet ik zien hoe je servo's kunt aansturen
Hiervoor moet je de Servo bibliotheek hebben toegevoegd in Arduino.
Dat doe je via bibliotheek beheer of library manager in het Engels.
// Servo test programma voor de Ghost Trap // voor het schema, zie www.bartvenneker.nl #include <Servo.h> Servo Rdoor; Servo Ldoor; void setup() { } void loop() { DoorsOpen(); delay(1000); DoorsClose(); delay(1000); } void DoorsOpen(){ Rdoor.attach(2,544,2550); // rechter servo op arduino pin 2 Ldoor.attach(3,544,2500); // linker servo op arduino pin 3 Rdoor.write(180); Ldoor.write(30); delay(500); Rdoor.detach(); Ldoor.detach(); } void DoorsClose(){ Rdoor.attach(2,544,2500); // rechter servo op arduino pin 2 Ldoor.attach(3,544,2550); // linker servo op arduino pin 3 Rdoor.write(30); Ldoor.write(180); delay(500); Rdoor.detach(); Ldoor.detach(); }
Display test 1, de fake led array
In de derde video laat ik zien dat ik de led array simuleer met een OLED display.
Daarvoor maakte ik eerst een testprogramma, zie hier..
Voor deze sketch moet je de Adafruit SSD1306 bibliotheek en de Adafruit GFX bibliotheek hebben toegevoegd in Arduino.
Dat doe je via bibliotheek beheer of library manager in het Engels.
// Test programma voor de LED Array in de Ghost trap. // Voor schema, zie www.BartVenneker.nl #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #define yellowled A3 // de dikke gele LED zit op A3 // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) Adafruit_SSD1306 display(128, 32, &Wire, -1); // mijn oled display is 128x32 pixels groot void setup() { pinMode(yellowled,OUTPUT); digitalWrite(yellowled,LOW); if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 for(;;); // Don't proceed, loop forever } // Clear the display buffer display.clearDisplay(); display.display(); } void loop() { // simulate the led bar array for (int y=0 ; y<11; y++){ ledbar(y); delay(100); } // activate the big yellow led. digitalWrite(yellowled,HIGH); delay(2000); // reset the led bar ledbar(0); // deactivate the big yellow led digitalWrite(yellowled,LOW); delay(5000); } void ledbar(int b){ // Deze void tekent een aantal (aantal = b) afgeronde rechthoekjes // op het scherm if (b > 11) {b=11;} // maximaal 11 int x=4; // de startpositie is 4 (4 pixels in de x richting) display.clearDisplay(); for (int v = 0; v < b; v++){ display.fillRoundRect(x+(v*12) , 0, 9, 32,3, SSD1306_INVERSE); } display.display(); }
Display test 2, de batterij
In de laatste video bouw ik de oplaadfunctie en toon ik hoe ik de batterij op het display animeer. Hier is dat programma.
Ook hiervoor moet je de Adafruit SSD1306 bibliotheek en de Adafruit GFX bibliotheek hebben toegevoegd in Arduino.
Dat doe je via bibliotheek beheer of library manager in het Engels.
#include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) Adafruit_SSD1306 display(128, 32, &Wire, -1); // mijn display is 128x32 pixels void setup() { // Initialize the display: if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 for(;;); // Don't proceed, loop forever } display.clearDisplay(); // Clear the display buffer display.display(); // transfer the buffer to screen } void loop() { // draw the battery display.clearDisplay(); display.drawRoundRect(20 , 0, 60, 32,5, SSD1306_WHITE); display.drawRoundRect(21 , 1, 58, 30,5, SSD1306_WHITE); display.drawRect(80 , 10, 8, 14, SSD1306_WHITE); display.drawRect(80 , 11, 7, 12, SSD1306_WHITE); display.drawFastVLine(80,12,10,SSD1306_BLACK); display.drawFastVLine(79,12,10,SSD1306_BLACK); display.drawFastVLine(78,12,10,SSD1306_BLACK); display.display(); delay(500); // Fill the battery for (int x = 22; x < 78 ; x++){ display.drawFastVLine(x,2,28,SSD1306_WHITE); delay(50); display.display(); } for (int x = 78; x < 86 ; x++){ display.drawFastVLine(x,10,12,SSD1306_WHITE); delay(50); display.display(); } delay(1000); // Display FULL inside battery display.setCursor(27, 10); display.setTextColor(SSD1306_BLACK); display.setTextSize(2); display.print("FULL"); display.display(); delay(3000); }
Sound Test
In de ghost trap zit een geluidsbordje dat kleine geluidseffecten kan afspelen
Het bordje maakt gebruik van een seriele interface en is dus eenvoudig aan te spreken... dat wil zeggen, als de commando's niet zo onnodig ingewikkeld waren
In dit test programma geef ik je twee eenvoudige procedures: een om het volume in te stellen en een om een geluid af te spelen. Wat heb je nog meer nodig?
// Testprogramma voor het sound bordje // voor meer info en schema, www.BartVenneker.nl #include <SoftwareSerial.h> SoftwareSerial Serial1(0, 12); void setup() { Serial1.begin(9600); volume(18); //Volume settings 0 - 30 } void loop() { play(1); // Speel de eerste track delay(5000); play(2); // Speel de tweede track delay(5000); } void play(unsigned char Track){ unsigned char play[6] = {0xAA,0x07,0x02,0x00,Track,Track+0xB3}; Serial1.write(play,6); } void volume( unsigned char vol){ unsigned char volume[5] = {0xAA,0x13,0x01,vol,vol+0xBE}; Serial1.write(volume,5); }
Versie 1.5 met voetpedaal ondersteuning
26-02-2023: Nieuwe firmware met ondersteuning voor een voetpedaal.
In deze video laat ik zien hoe je een voetpedaal zou kunnen toevoegen aan de Ghosttrap.
Schema Hier is mijn nieuwe schema. Klik op het plaatje voor een grotere versie
Arduino Code
// This is the arduino software for my Ghost trap. // version 1.5 // See www.BartVenneker.nl for the schematic and more info #include <Servo.h> #include <SoftwareSerial.h> #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <Adafruit_NeoPixel.h> #define yellowled A3 #define redled 6 #define NeoPixelsPin 8 #define NUMPIXELS 32 SoftwareSerial Serial1(0, 12); // Rx=not used, Tx=12 Adafruit_NeoPixel pixels(NUMPIXELS, NeoPixelsPin, NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel pixels2(8, 13, NEO_GRB + NEO_KHZ800); // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) Adafruit_SSD1306 display(128, 32, &Wire, -1); Servo Rdoor; Servo Ldoor; unsigned long playtime; boolean fullBattery = false; boolean footpedal = false; void setup() { //Serial.begin(9600); pinMode(yellowled,OUTPUT); digitalWrite(yellowled,LOW); pinMode(redled,OUTPUT); digitalWrite(redled,HIGH); pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) pixels.clear(); // Set all pixel colors to 'off' pixels.show(); pixels2.begin(); pixels2.clear(); pixels2.show(); Serial1.begin(9600); volume(0); //Volume settings 0 - 30 DoorsClose(100); delay(100); // initialize the display. if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 for(;;); // Don't proceed, loop forever } // Clear the display display.clearDisplay(); display.display(); // Find out if the knobs are set to charge mode while (inChargeMode()){ charging(); } display.clearDisplay(); display.display(); Serial.begin(9600); if (analogRead(A1) > 1000) footpedal=true; } void drawBattery(boolean clearFirst){ // Draw the battery if (clearFirst) { display.clearDisplay(); } display.drawRoundRect(20 , 0, 60, 32,5, SSD1306_WHITE); display.drawRoundRect(21 , 1, 58, 30,0, SSD1306_WHITE); display.drawRect(80 , 10, 8, 14, SSD1306_WHITE); display.drawRect(80 , 11, 7, 12, SSD1306_WHITE); if (clearFirst){ display.drawFastVLine(80,12,10,SSD1306_BLACK); display.drawFastVLine(79,12,10,SSD1306_BLACK); display.drawFastVLine(78,12,10,SSD1306_BLACK); } display.display(); } void chargeAnimation(){ // charging the battery: for (int x=22;x< 78 ; x++) { display.drawFastVLine(x,2,28,SSD1306_WHITE); display.display(); delay(50); } for (int x=78; x< 86; x++){ display.drawFastVLine(x,10,12,SSD1306_WHITE); display.display(); delay(50); } delay(1000); } void drawFullBattery(){ for (int x=22;x< 78 ; x++) { display.drawFastVLine(x,2,28,SSD1306_WHITE); } for (int x=78; x< 86; x++){ display.drawFastVLine(x,10,12,SSD1306_WHITE); } display.setCursor(27, 10); display.setTextColor(SSD1306_BLACK); display.setTextSize(2); display.print("FULL"); display.display(); delay(500); } boolean inChargeMode(){ // Get the average of 10 data points. long b = 0; for (int x=0; x< 10 ; x++){ int c = analogRead(A2); b += c; delay(100); } b = b / 10; if (b < 100) {return true;} return false; } void charging(){ // pin A0 is attached to the charge led on the charge regulator // the green charge led is removed // See www.BartVenneker.nl for more info int a = analogRead(A0); // a < 300 = No charger attached // a > 300 = Charging // a > 600 = Full if (a < 300) { // No charger attached, just show empty battery drawBattery(true); fullBattery = false; return; } // overwrite the messurement when we have seen that the battery is full. if (fullBattery) {a = 700;} if (a <600) { // Charging, show the charge animantion drawBattery(true); chargeAnimation(); return; } // Battery is full // Show the full battery drawBattery(false); drawFullBattery(); fullBattery = true; return; } void play(unsigned char Track){ unsigned char play[6] = {0xAA,0x07,0x02,0x00,Track,Track+0xB3}; Serial1.write(play,6); playtime = millis(); } void volume( unsigned char vol){ unsigned char volume[5] = {0xAA,0x13,0x01,vol,vol+0xBE}; Serial1.write(volume,5); } void DoorsOpen(int d){ Rdoor.attach(2,544,2550); Ldoor.attach(3,544,2500); Rdoor.write(180); Ldoor.write(30); delay(d); Rdoor.detach(); Ldoor.detach(); } void DoorsClose(int d){ Rdoor.attach(2,544,2500); Ldoor.attach(3,544,2550); Rdoor.write(30); Ldoor.write(180); delay(d); Rdoor.detach(); Ldoor.detach(); } void loop() { while(analogRead(A1) > 1000) { delay(10); pixels2.setPixelColor(0, pixels.Color(255, 0, 0)); pixels2.show(); } pixels2.setPixelColor(0, pixels.Color(0, 0, 255)); pixels2.show(); volume(20); // play the catch sound play(3); // duration 8.25 seconds delay(550); // open the doors DoorsOpen(1000); // While the sound is playing, make the led rings yellow // in time with the whoosh sounds :-) delay(200); fadeIn(1, 255, 255, 0, 8); delay(650); ringColor(1, 100, 100,0); fadeIn(2, 255, 255, 0, 8); delay(650); ringColor(2, 100, 100,0); fadeIn(3, 255, 255, 0, 8); delay(650); ringColor(3, 100, 100,0); fadeIn(4, 255, 255, 0 ,8); // close the door after 6.5 seconds while (millis() < playtime + 6200) {delay(1);} DoorsClose(500); // Set all led rings to full RED ringColor(1, 255, 0,0); ringColor(2, 255, 0,0); ringColor(3, 255, 0,0); ringColor(4, 255, 0,0); // wait for the sound to stop playing while (millis() < playtime + 7700) {delay(1);} // simulate the led bar array for (int y=0 ; y<11; y++){ ledbar(y); delay(100); } // activate the big yellow led digitalWrite(yellowled,HIGH); volume(8); // play the beep sound DoorsClose(300); play(2); while (millis() < playtime + 5000){ digitalWrite(redled,LOW); delay(250); digitalWrite(redled,HIGH); delay(250); } ledbar(0); pixels.clear(); // Set all pixel colors to 'off' pixels.show(); // the show is over. Now we can play with the settings knob.. parameters(); } void parameters(){ pixels2.setPixelColor(0, pixels.Color(0, 255, 0)); pixels2.show(); volume(0); unsigned long blinktime = millis(); unsigned long changetime = millis(); unsigned long blinkRedLed = millis(); int grid= analogRead(A2); int lastgrid = grid; String parameter = "tesla grid"; int lasty=0; boolean nextparam = false; randomSeed(grid); int k = random(1,5); if (k == 1){ parameter="tesla grid";} if (k == 2){ parameter="neon field";} if (k == 3){ parameter="iq strings";} if (k == 4){ parameter="delta rays";} while(true){ if (footpedal and analogRead(A1) < 1000) { while (analogRead(A1) < 1000) { delay(10); }; delay(100); return; } if (millis() > blinkRedLed + 5000){ blinkRedLed = millis(); digitalWrite(redled,LOW); delay(100); digitalWrite(redled,HIGH); } grid= analogRead(A2); if (abs(grid - lastgrid) > 20){ // the knob is turning. changetime = millis() + 3000; lastgrid = grid; nextparam = true; } display.clearDisplay(); displayText(parameter); int y = map(grid,0,1023,1,122); if (abs(lasty-y)>3) { // play a click sound lasty = y; play(1); // click delay(100); volume(10); } for (int x = 0; x < y ; x=x+6){ display.fillRect(x,20,4,12,SSD1306_WHITE); } if (millis() > changetime) { display.clearDisplay(); y = 0; if (nextparam){ k=k+1; if (k==5) k=1; if (k == 1){ parameter="tesla grid";} if (k == 2){ parameter="neon field";} if (k == 3){ parameter="iq strings";} if (k == 4){ parameter="delta rays";} nextparam=false; } } display.display(); if (y > 100){ // blink the yellow led if (millis() + 200 > blinktime) {digitalWrite(yellowled,LOW);} if (millis() > blinktime) {digitalWrite(yellowled,HIGH); blinktime=millis() + 400;} } else {digitalWrite(yellowled,LOW);} } } void displayText(String p){ display.setCursor(0, 0); display.setTextColor(SSD1306_WHITE); display.setTextSize(2); display.print(p); } void fadeIn(int pos, int r, int g, int b, int steps) { // Fade in for the neopixel rings int s = (pos-1) * 8; for (int q=0; q < steps ; q++){ int ri = (r / steps) * q; int gi = (g / steps) * q; int bi = (b / steps) * q; for (int i =s; i<(s+8) ; i++){ pixels.setPixelColor(i, pixels.Color(ri, gi, bi)); } pixels.show(); delay(50); } // make sure to display the end color ringColor(pos,r,g,b); } void ringColor(int pos, int r, int g, int b){ // make all the leds in this ring the same color // pos = 1,2,3 or 4 // r =red, g=green, b=blue 0~255 int s = (pos-1) * 8; for (int i =s; i<(s+8) ; i++){ pixels.setPixelColor(i, pixels.Color(r, g, b)); } pixels.show(); } void ledbar(int b){ if (b > 11) {b=11;} int x=4; display.clearDisplay(); for (int v = 0; v < b; v++){ display.fillRoundRect(x+(v*12) , 0, 9, 32,3, SSD1306_WHITE); } display.display(); }