Before you know it, the doorbell rings and it's "trick or treat?" again.
Halloween always comes so suddenly. Usually, I only manage to buy a few pieces of candy. But this year I want to make something that I can use to scare the kids a little. The idea: When approaching (motion detector or range finder) you first hear the scream of a crow, and then the beast flies over your heads.
We need hardware:
1 |
|
old. |
|
1 |
|
1 |
Micro Controller Nano or own choice |
1 |
Mini MP3 player plus µSD card |
1 |
|
1 |
Robust servo e.g. MG996R |
- |
10 kOhm potentiometer, cable |
div. |
Handicraft material, e.g. popsicle stick, toilet roll, string, reel |
The "flight of the crow" is simulated by moving a dummy with a pulley on a string. The string is moved higher or lower on one side with a servo arm. To get enough slope, I screwed on the wooden handle from my favorite ice cream as an extension of the servo arm.
The good news for the less talented hobbyist is the fact that it gets dark early on October 31. So the "crow" doesn't need to be perfectly replicated, a loo roll, some wire and black cloth/plastic bag is perfectly sufficient for the illusion.
Therefore we can start with the programming of the sketch. I don't expect any difficulties with the program lines for the trigger, basically I will use parts of the example sketch "button" will be used. Therefore I concentrate first on the MP3 player. For this I download from the product page the datasheet and the schematics. Since I need a breadboard for the MP3-player anyway, I decide for a Nano as microcontroller. I use the same pins as on the schematic, so D10 and D11.
To find a suitable library, I enter DFPlayer in the search line of the library manager of the Arduino IDE. The most recent library is the one from Angelo called DFRobotDFPLayerMini. After installation you have basically the same information that you can find on github at https://github.com/DFRobot/DFRobotDFPlayerMini including some examples and a pdf document with the detailed description of the mp3 player.
Andreas Wolter had described a nice application with good explanations also in his blog post from 29/03/2021:
I am amazed at the many possibilities of the small mp3 player with µSD card reader. Most of the functions or connections I will not use at all. More about this later.
From the website https://quicksounds.com/library/sounds/crow I download a suitable sound and store it on the µSD card in the directory mp3 as 0001.mp3 directory. In addition a scary laughter as 0002.mp3to increase the Halloween mood. Here are the links to the sounds I chose: 0001.mp3 resp. 0002.mp3
I start with the example sketch GetStarted and modify it with regard to my requirements.
Here first the pinout of the mp3-pPlayer with description:
From the 16 pins I use only pin 1 and 7 for the power supply, so 5V and Ground, a small speaker with max. 3 Watt is connected to pin 6 and 8, and the data transfer from the microcontroller is done via pins 2 and 3, the serial interface UART.
Since the AVR microcontrollers with ATMega328 have only one serial hardware interface, I use pins 10 and 11 for a software serial interface. As usual, RX and TX are connected crosswise and (watch out:) between Nano D11 (TX) and mp3-player pin 2 (RX) there is a resistor with 1 kOhm because of the remark 3.3V TTL level (see above).
Here now the modified example 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 myDFPlayer.stop(); } void loop() { player(); delay(20000); Serial.println("Again"); }
My changes are limited to the use of a pot for volume control at input A0, mapped to the value range 0 to 30 of the program library, and the relocation of the essential program lines for the player to a self-defined function player()which is called by the main program.
In the next step I want to include the motion detector, which should first trigger the crowing sound of the mp3 player and then operate the servo for the string.
The motion sensor works like a switch. Sensitivity of the sensor and duty cycle can be adjusted at two trim pots. We only need the switch-on signal to trigger the planned sequence. I use the program example „button" (Examples->02.Digital) and connect the signal pin OUT to D2. The power supply is done with 5V and Ground.
Here the sketch, where the LED_BUILTIN is switched on when a movement is detected. As said, later we only need 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); } }
Afterwards this sketch is "married" with the program code of the MP3 player (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"); } }
There is also a sample sketch for the servo that I can modify. Also here I move the main part of the program "Servo_Sweep" into two functions to move the servo quickly, but not too abruptly, to the positions 0° and 180° respectively. The length of the servo arm depends of course on the length of the string; a certain gradient is necessary to make the bird dummy "fly" fast enough. Here is the modified 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); }
At the end this part is also integrated into the sketch with motion detector and mp3 player and tried out. (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 first mp3 myDFPlayer.stop(); } 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"); } }
In the main program void loop() first the trigger from the motion detector is waited for, then the mp3 player is activated. Since this plays the mp3 file independently of the microcontroller, a few seconds delay are inserted before the servo arm swings up (function servoUp()) to set the dummy crow in motion. After a certain time the dummy is brought back to the start position with servoDown() and the next crowd of children can be scared.
Due to the structural situation in our house, the implementation did not work out as planned. The distance between the end points of the leash is too big - so there is hardly any gradient, and the dummy, which can be used safely due to the low height of the leash, is too light. First alternative solution: move the line together with the dummy with a motor and pulley. Second alternative solution: attach a light U-profile to the servo and swivel the dummy. This works fine for us.
Here is the link to the slightly modified sketch (angle range 10° to 170° and insert laughter)
(download).
Finally the whole schematic and the picture of our crow dummy, consisting of a hanger, two bags and a felted head; a witch with a broom would be a good alternative. Have fun building it.
Here is another video that was taken during the day. It is an experimental setup. Of course, it's dark on Halloween and there will be some decorations. You can hear the sounds from the MP3 player. The dummy moves after the motion sensor has detected my movement towards the house.
13 comments
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.