Ehe man sich versieht, klingelt es an der Tür und es heißt wieder „Süßes oder Saures?“
Halloween kommt immer so plötzlich. Meist schaffe ich es nur, ein paar Süßigkeiten zu kaufen. Aber dieses Jahr möchte ich etwas basteln, womit ich die Kinder ein wenig erschrecken kann. Die Idee: Bei Annäherung (Bewegungsmelder oder Entfernungsmesser) hört man zunächst das Geschrei einer Krähe, und dann fliegt das Biest auch schon über die Köpfe hinweg.
Wir brauchen an Hardware:
1 |
|
alt. |
|
1 |
|
1 |
Mikro Controller Nano oder eigene Wahl |
1 |
Mini MP3-Player plus µSD-Karte |
1 |
|
1 |
Robuster Servo z.B. MG996R |
- |
10 kOhm Poti, Kabel |
div. |
Bastelmaterial, z.B. Eisstiel, Klo-Rolle, Schnur, Rolle |
Der „Flug der Krähe“ wird simuliert, indem eine Attrappe mit einer Laufrolle auf einer Schnur bewegt wird. Dabei wird die Schnur an einer Seite mit einem Servo-Arm höher oder tiefer gestellt. Um genügend Gefälle zu erzielen, habe ich den Holzstiel von meinem Lieblingseis als Verlängerung des Servo-Arms angeschraubt.
Die gute Nachricht für den wenig talentierten Bastler ist die Tatsache, dass es am 31. Oktober früh dunkel wird. Die „Krähe“ muss also nicht perfekt nachgebildet werden, eine Klo-Rolle, etwas Draht und schwarzer Stoff/Plastiktüte genügen für die Illusion vollkommen.
Deshalb können wir uns zunächst auf die Programmierung des Sketches stürzen. Bei den Programmzeilen für den Auslöser erwarte ich keine Schwierigkeiten, im Wesentlichen werde ich Teile des Beispiel-Sketches „button“ verwenden. Deshalb konzentriere ich mich zunächst auf den MP3-Player. Dazu lade ich von der Produktseite das Datenblatt und die Schaltung (Schematics) herunter. Da ich für den MP3-Player ohnehin ein Breadboard benötige, entscheide ich mich für einen Nano als Mikrocontroller. Dabei benutze ich die gleichen Pins wie auf dem Schaltbild, also D10 und D11.
Um eine geeignete Programm-Bibliothek (library) zu finden, gebe ich im Bibliotheksverwalter der Arduino-IDE in der Suchzeile DFPlayer ein. Am aktuellsten ist die Bibliothek von Angelo mit Namen DFRobotDFPLayerMini. Nach der Installation hat man im wesentlichen die gleichen Informationen, die man auf github unter https://github.com/DFRobot/DFRobotDFPlayerMini findet, einschließlich einiger Beispiele und eines pdf-Dokuments mit der ausführlichen Beschreibung des mp3-Players.
Andreas Wolter hatte eine schöne Anwendung mit guten Erklärungen auch in seinem Blog-Beitrag vom 29.03.2021 beschrieben:
Ich staune über die vielfältigen Möglichkeiten des kleinen mp3-Players mit µSD-Card-Reader. Die meisten Funktionen bzw. Anschlüsse werde ich gar nicht benutzen. Mehr dazu später.
Von der Internetseite https://quicksounds.com/library/sounds/crow lade ich einen geeigneten Sound herunter und speichere diesen auf der µSD-Karte im Verzeichnis mp3 als 0001.mp3 ab. Dazu noch ein schauriges Gelächter als 0002.mp3, um ggf. die Halloween-Stimmung zu steigern. Hier die Links zu den von mir gewählten Geräuschen: 0001.mp3 bzw. 0002.mp3
Ich beginne mit dem Beispiel-Sketch GetStarted und modifiziere diesen im Hinblick auf meine Erfordernisse.
Hier zunächst die Pinbelegung des mp3-pPlayers mit Beschreibung:
Von den 16 Pins benutze ich nur Pin 1 und 7 für die Spannungsversorgung, also 5V und Ground, an Pin 6 und 8 wird ein kleiner Lautsprecher mit max. 3 Watt angeschlossen, und die Datenübertragung vom Mikrocontroller erfolgt über Pins 2 und 3, die serielle Schnittstelle UART.
Da die AVR-Mikrocontroller mit ATMega328 nur eine serielle Hardware-Schnittstelle haben, benutze ich die Pins 10 und 11 für eine SoftwareSerial-Schnittstelle. Wie üblich, werden RX und TX über Kreuz verbunden und (aufgepasst:) zwischen Nano D11 (TX) und mp3-Player Pin 2 (RX) kommt noch ein Widerstand mit 1 kOhm wegen der Bemerkung 3,3V TTL level (s.o.).
Hier nun der modifizierte Beispiel-Sketch (download):
#include "Arduino.h" #include "SoftwareSerial.h" #include "DFRobotDFPlayerMini.h" // declare global variables uint16_t vol; SoftwareSerial mySoftwareSerial(10, 11); // RX, TX DFRobotDFPlayerMini myDFPlayer; void printDetail(uint8_t type, int value); void setup() { mySoftwareSerial.begin(9600); Serial.begin(9600); Serial.println(); Serial.println(F("DFRobot DFPlayer Mini Demo")); Serial.println(F("Initializing DFPlayer")); myDFPlayer.begin(mySoftwareSerial); //) { //Use SoftwareSerial to communicate with mp3. Serial.println(F("DFPlayer Mini online.")); } void player() { vol = map(analogRead(A0),0,1023,0,30); Serial.print("volume: "); Serial.println(vol); myDFPlayer.volume(vol); //Set volume value. From 0 to 30 myDFPlayer.play(1); //Play the first mp3 } void loop() { player(); delay(20000); Serial.println("Again"); }
Meine Veränderungen beschränken sich auf die Verwendung eines Potis für die Lautstärkeregelung an Eingang A0, gemapped auf den Wertebereich 0 bis 30 der Programm-Bibliothek, sowie die Verlegung der wesentlichen Programmzeilen für den Player in eine selbstdefinierte Funktion player(), die vom Hauptprogramm aufgerufen wird.
Im nächsten Schritt möchte ich den Bewegungsmelder einbinden, der zunächst das Krähengeräusch des mp3-Players triggern und danach den Servo für die Schnur betätigen soll.
Der Bewegungsmelder funktioniert wie ein Schalter. Empfindlichkeit des Sensors und Einschaltdauer können an zwei Trimm-Potis eingestellt werden. Wir benötigen nur das Einschaltsignal zum Triggern des geplanten Ablaufs. Ich verwende das Programmbeispiel „button“ (Beispiele->02.Digital) und schließe den Signal-Pin OUT an D2 an. Die Spannungsversorgung erfolgt mit 5V und Ground.
Hier der Sketch, bei dem die LED_BUILTIN beim Erkennen einer Bewegung eingeschaltet wird. Wie gesagt, benötigen wir später nur if (buttonState == HIGH)
// constants won't change. They're used here to set pin numbers: const int buttonPin = 2; // the number of the pushbutton pin const int ledPin = 13; // the number of the LED pin // variables will change: int buttonState = 0; // variable for reading the pushbutton status void setup() { // initialize the LED pin as an output: pinMode(ledPin, OUTPUT); // initialize the pushbutton pin as an input: pinMode(buttonPin, INPUT); } void loop() { // read the state of the pushbutton value: buttonState = digitalRead(buttonPin); // check if the pushbutton is pressed. If it is, the buttonState is HIGH: if (buttonState == HIGH) { // turn LED on: digitalWrite(ledPin, HIGH); } else { // turn LED off: digitalWrite(ledPin, LOW); } }
Anschließend wird dieser Sketch mit dem Programmcode des MP3-Players "verheiratet" (download).
#include "Arduino.h" #include "SoftwareSerial.h" #include "DFRobotDFPlayerMini.h" // declare global variables uint16_t vol; const int buttonPin = 2; // the number of the pushbutton pin int buttonState = 0; // variable for reading the pushbutton status SoftwareSerial mySoftwareSerial(10, 11); // RX, TX DFRobotDFPlayerMini myDFPlayer; void printDetail(uint8_t type, int value); void setup() { Serial.begin(9600); mySoftwareSerial.begin(9600); // initialize the pushbutton pin as an input: pinMode(buttonPin, INPUT); myDFPlayer.begin(mySoftwareSerial); //) { //Use SoftwareSerial to communicate with mp3. Serial.println(F("DFPlayer Mini online.")); } void player() { vol = map(analogRead(A0),0,1023,0,30); Serial.print("volume: "); Serial.println(vol); myDFPlayer.volume(vol); //Set volume value. From 0 to 30 myDFPlayer.play(1); //Play the first mp3 myDFPlayer.stop(); } void loop() { // read the state of the pushbutton value: buttonState = digitalRead(buttonPin); // check if the pushbutton is pressed. If it is, the buttonState is HIGH: if (buttonState == HIGH) { player(); delay(20000); Serial.println("Again"); } }
Auch für den Servo gibt es einen Beispiel-Sketch, den ich modifizieren kann. Auch hier verschiebe ich den Hauptteil des Programms „Servo_Sweep“ in zwei Funktionen, um den Servo zügig, aber nicht zu abrupt jeweils in die Stellungen 0° bzw. 180° zu fahren. Die Länge des Servo-Arms hängt natürlich von der Länge der Schnur ab; ein gewisses Gefälle ist nötig, damit die Vogel-Attrappe schnell genug „fliegt“. Hier der modifizierte Sketch (download):
#include <Servo.h> Servo myservo; // create servo object to control a servo // twelve servo objects can be created on most boards int pos = 0; // variable to store the servo position void setup() { Serial.begin(9600); myservo.attach(13); // attaches the servo on pin 9 to the servo object myservo.write(0); } void servoUp() { for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree myservo.write(pos); // tell servo to go to position in variable 'pos' delay(10); // waits 10 ms for the servo to reach the position } } void servoDown() { for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees myservo.write(pos); // tell servo to go to position in variable 'pos' delay(10); // waits 10 ms for the servo to reach the position } } void loop() { servoUp(); delay(5000); servoDown(); delay(5000); }
Am Ende wird auch dieser Teil in den Sketch mit Bewegungsmelder und mp3-Player integriert und ausprobiert. (download)
/*************************************************** * A spooky Halloween joke with voice of a crow from mp3 player, * a crow mock-up moved on a string by servo * triggered by motion sensor * for AZ-Delivery * This example code is in the public domain. ****************************************************/ #include "Arduino.h" #include "SoftwareSerial.h" #include "DFRobotDFPlayerMini.h" #include <Servo.h> Servo myservo; // create servo object to control a servo // declare global variables uint16_t vol; const int buttonPin = 2; // the number of the pushbutton pin int buttonState = 0; // variable for reading the pushbutton status int pos = 0; // variable to store the servo position SoftwareSerial mySoftwareSerial(10, 11); // RX, TX DFRobotDFPlayerMini myDFPlayer; void printDetail(uint8_t type, int value); void setup() { Serial.begin(9600); mySoftwareSerial.begin(9600); // initialize the pushbutton pin as an input: pinMode(buttonPin, INPUT); myDFPlayer.begin(mySoftwareSerial); //) { //Use SoftwareSerial to communicate with mp3. Serial.println(F("DFPlayer Mini online.")); myservo.attach(13); // attaches the servo on pin 13 to the servo object myservo.write(0); } void player(int i) { vol = map(analogRead(A0),0,1023,0,30); Serial.print("volume: "); Serial.println(vol); myDFPlayer.volume(vol); //Set volume value. From 0 to 30 myDFPlayer.play(i); //Play the mp3 file } void servoUp() { for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees // in steps of 1 degree myservo.write(pos); // tell servo to go to position in variable 'pos' delay(10); // waits 10 ms for the servo to reach the position } } void servoDown() { for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees myservo.write(pos); // tell servo to go to position in variable 'pos' delay(10); // waits 10 ms for the servo to reach the position } } void loop() { // read the state of the pushbutton value: buttonState = digitalRead(buttonPin); // check if the pushbutton is pressed. If it is, the buttonState is HIGH: if (buttonState == HIGH) { player(1); delay(8000); servoUp(); delay(20000); servoDown(); delay(20000); Serial.println("Again"); } }
Im Hauptprogramm void loop() wird zunächst auf den Trigger vom Bewegungsmelder gewartet, dann der mp3-Player aktiviert. Da dieser die mp3-Datei unabhängig vom Mikrocontroller abspielt, werden einige Sekunden delay eingefügt, bevor der Servo-Arm nach oben schwingt (Funktion servoUp()), um die Krähen-Attrappe in Bewegung zu setzen. Nach einer gewissen Zeit wird die Attrappe mit servoDown() wieder in die Startposition gebracht und die nächste Kinderschar kann erschreckt werden.
Aufgrund der baulichen Situation bei uns hat die Umsetzung nicht so geklappt, wie geplant. Zu groß der Abstand zwischen den Endpunkten der Leine - damit kaum Gefälle, und zu leicht die Attrappe, die aufgrund geringer Höhe der Leine gefahrlos benutzt werden kann. Erste alternative Lösung: Leine samt Attrappe mit einem Motor und Umlenkrolle bewegen. Zweite alternative Lösung: leichtes U-Profil am Servo befestigen und die Attrappe schwenken. Das klappt bei uns prima.
Hier der Link zu dem leicht modifizierten Sketch (Winkelbereich 10° bis 170° und Einfügen Gelächter)
(download).
Zum Schluss noch der gesamte Schaltplan sowie das Bild unserer Krähen-Attrappe, bestehend aus einem Bügel, zwei Tüten und einem gefilzten Kopf; eine Hexe mit Besen wäre eine gute Alternative. Viel Spaß beim Nachbauen.
Es folgt hier noch ein Video, dass am Tage aufgenommen wurde. Es handelt sich um einen Versuchsaufbau. An Halloween ist es natürlich dunkel und es wird auch etwas geschmückt sein. Man hört die Geräusche aus dem MP3 Player. Die Attrappe bewegt sich, nachdem der Bewegungssensor meine Bewegung Richtung Haus detektiert hat.
13 commenti
Bernd Albrecht
@ Bernd-Steffen Großmann. Danke für die Hinweise. Jeder kann den Sketch nach seinen Wünschen modifizieren. Beleuchtung mache ich separat mit RGBLED Ring.
@ all: der stop()-Befehl für den MP3-Player macht nur Sinn, wenn der delay(x)-Befehl zuvor das Abspielen für x Sekunden ermöglicht. Inzwischen in den Beispiel-Sketchen gelöscht.
Bernd Albrecht
@ Chris: Im eBook (https://www.az-delivery.de/products/mp3-player-modul-kostenfreies-e-book)
kann man das volle Potenzial des MP3-Players entdecken. Der direkt angeschlossene Lautsprecher mit max. 3W ist nur eine Möglichkeit. Stereo für Kopfhörer oder externen Verstärker gibt es an anderen Pins.
Eric
video works: click on enlarge button, top right corner and press play again :-)
Bernd-Steffen Großmann
Was sagen Sie zu dem Hinweis mit dem Stop-Befehl? Und zu meinem Erweiterungsvorschlag bzgl. der LEDs?
Bernd Albrecht
@ all: Vielen Dank für das positive Feedback zu der Idee.
Zwei kleine Hürden waren zu nehmen: 1. Im Schaltbild fehlte die Verbindung vom Poti zum Eingang A0. Sorry.
2. Es gibt verschiedene Ausführungen des PIR-Sensors. Bitte die Beschriftung der Pinbelegung beachten. Ggf. befindet sich diese auf der Sensorseite unter der Plastikabdeckung; diese ist nur aufgesteckt.
Bernd-Steffen Großmann
Noch eine weitere Ergänzung: die Beschaltung von PIR-Bewegungs-Sensor im “Schaltbild” ist verkehrt: an den linken Pin (von vorn gesehen) kommt Masse (GND) und rechts 3-5 V (5P)!
Außerdem fehlt die Verbindung von Schleifer (Mitte) des Potis an A0 von Arduino. (Schlaumeier-Modus wieder aus ;0) )
Bernd-Steffen Großmann
Hallo Herr Albrecht, ich habe jetzt angefangen, das Projekt nachzubauen. Bei ersten Sketch bin ich auf einen Fehler gestoßen: in Zeile 51 haben Sie einen Stop-Befehl für den DF-Player eingefügt.
50 – myDFPlayer.play(i); //Play the first mp3
51 – myDFPlayer.stop();
Der bewirkt, dass der Player kurz zur Wiedergabe ansetzt, aber sofort wieder stoppt! Wenn der auskommentiert (unwirksam) gemacht wird, dann funktioniert die Wiedergabe des ersten Sound-Files.
Mit freundlichen Grüßen,
Bernd-Steffen Großmann
Chris
Schönes Projekt, ob für Halloween oder angepasst an gewünschte Themen. :)
Ich frage mich was ich an Soundqualität von dem Setup erwarten kann? Für die Box mit kurzer Distanz wird es als Gag ausreichen.
Wenn es lauter werden soll und von der Soundqualität mit Smartphone- und Bluetooth-Lautsprecher-Kombi mithalten soll, was wäre ein geeignetes Setup (sowohl kabelgebunden/ per Bluetooth)?
Bernd-Steffen Großmann
Hallo Herr Albrecht, lustige Idee! Werde ich mal ausprobieren. Noch schauriger wird es bestimmt, wenn an die vier PWM-Ausgänge vom Arduino je 2 blaue und 2 rote LEDs angeschlossen werden und, durch Zufallszahlen angesteuert, schön schaurig flackern.
Er
Mirko
Meine Fragen haben sich bereits geklärt. Beim PIR ist die Beschriftung für Plus/Minus vertauscht aufgedruckt. Die Geschwindigkeit vom Motor konnte ich anpassen. Bleibt nur der Fehler in der Fritzing-Zeichnung bzgl. Poti. :-)
Mirko
In der Fritzing-Zeichnung fehlt die Verbindung vom Poti auf A0. Der Bewegungsmelder will bei mir noch nicht und das Programm läuft in Endlosschleife als wenn Bewegung da wäre. Der Motor ist beim ersten Lauf nach dem Reset schnell und danach recht langsam. Woran könnte das liegen?
dirk
Hallo,
ich habe zwei Probleme:
1. Der Servo dreht regelmäßig abwechselnd 180 Grad nach links und ca. 10 sec. später nach rechts. Egal ob der Bewegungssensor angeschlossen ist oder nicht. Auch das Abdecken des Sensors mit Pappe ändert nichts. Audioausgabe funktioniert auch nicht.
2. Muss zwischen dem Poti und A0 keine Verbindung?
Joachim
Hätte gerne die Funktionsweise gesehen. Leider funktioniert das Video nicht.