A Shaky Bird

Looking into this now, I am beginning to realize that my efforts may have been better spent modifying one of those little "Dancing Santas" that they sell every year around Christmas - but at any rate:

I've purchase an Arduino Uno, a Paralax Motion Sensor, a MicroSD card, a WaveShare MicroSD Card Reader, and scavenged a vibration motor from an old game controller I had laying around.

As they parts may hint, I'm looking to create a project that detects motion, begins playing a sound, and about a second and a half into that sound, turns on the vibration motor for a few seconds.

The project will end up 'animating' (playing a sound and shaking, really) a toy turkey (a conversation piece for my hunting in-laws).

I feel confident in most of my canabilized code (combined publically available motion sensor tutorials, sound file tutorials, and am attempting to modify the LED blink code to wind my vibration motor up and then back down), but I'm not entirely sure how to make a 'loop within a loop'.

Attached below is my code: I'm hoping someone can help me incorporate the motor code (even further below) or simplify this without requiring me to purchase anymore hardware.

Drafted Code:

#include <pcmRF.h>
#include <TMRpcm.h>

#include <SD.h>                      // need to include the SD library
//#define SD_ChipSelectPin 53  //example uses hardware SS pin 53 on Mega2560
#define SD_ChipSelectPin 10  //using digital pin 4 on arduino nano 328
#include <TMRpcm.h>           //  also need to include this library...

const int sensorPin = 2;           // PIR Sensor is attached to digital pin 2
const int ledPin = 13;             // Built-in LED
const int ledBlinkTime = 500;      // Blink one for half a second while calibrating
int motor = 6;           // the pin that the motor is attached to
int strength = 0;    // how strong the motor is
int fadeAmount = 5;    // how many points to fade the motor by
 
TMRpcm tmrpcm;   // create an object for use in this sketch
char mychar;

// Wait for the seonsor to calibrate (20 - 60 seconds according to datasheet)
// 60 Seconds in milliseconds
const unsigned int calibrationTime = 60000;
 
void setup(){
 
  tmrpcm.speakerPin = 9; //11 on Mega, 9 on Uno, Nano, etc
  
    // declare pin 6 to be an output:
  pinMode(motor, OUTPUT);
 
  Serial.begin(9600);
  if (!SD.begin(SD_ChipSelectPin)) {  // see if the card is present and can be initialized:
    Serial.println("SD fail");  
    return;   // don't do anything more if not
  }
  tmrpcm.play("gobble.wav"); //the sound file "music" will play each time the arduino powers up, or is reset

  Serial.begin(115200);
  
  pinMode(sensorPin, INPUT);
  pinMode(ledPin, OUTPUT);
  
  // We need to wait one minute for the sensor to calibrate
  // Get out of view of the sensor for this duration!
  
  // Blink the LED while calibrating
  for (unsigned int i=0; i<calibrationTime; i+=ledBlinkTime*2) {
    digitalWrite(ledPin, HIGH);
    delay(ledBlinkTime);
    digitalWrite(ledPin, LOW);
    delay(ledBlinkTime);
  }
  
}
 
 
 
void loop(){  
  // Constantly check the state of pin 2
  // If it is HIGH the sensor is detecting motion
  if (digitalRead(sensorPin) == HIGH) {
    // Turn the LED on
    digitalWrite(ledPin, HIGH);
	
    // Play Spitting and Drumming Sound
    tmrpcm.play("spit.wav");
	
    // Wait a second and a half before shaking
    delay(1500);
	
	// Start Shaking
	// I somehow need to incorpoate the motor code into this section, but the motor code appears to rely on it's own repeating loop for functionality.
	
  } else {
    // Turn the LED off
    digitalWrite(ledPin, LOW);
  }
  

}

Motor Code:

// the loop routine runs over and over again forever:
void loop()  { 
  // set the strength of pin 6:
  analogWrite(motor, strength);    

  // change the strength for next time through the loop:
  strength = strength + fadeAmount;

  // reverse the direction of the fading at the ends of the fade: 
  if (strength == 0 || strength == 255) {
    fadeAmount = -fadeAmount ; 
  }     
  // wait for 30 milliseconds to see the dimming effect    
  delay(30);

Thank you very much for your time - I know I'm new here and tragically under skilled - but I'm hoping to improve on that.

Do you only want to run it a certain number of times, or run it indefinitely, until another condition arises where you want to stop it?

Arrch:
Do you only want to run it a certain number of times, or run it indefinitely, until another condition arises where you want to stop it?

I would like it run once per trigger (detected motion).
Basically, turkeys have this thing they do to assert themselves called "Drumming" (or, "Spitting and Drumming" to be technical). The spitting and drumming sound (as the name would suggest) includes a "tsk" noise and then a "whooo" sound that sort of winds up like a motor buzz and actually shakes the turkey's entire body for a few seconds.

That's what I'm trying to emulate.

JamesR7217:

Arrch:
Do you only want to run it a certain number of times, or run it indefinitely, until another condition arises where you want to stop it?

I would like it run once per trigger (detected motion).
Basically, turkeys have this thing they do to assert themselves called "Drumming" (or, "Spitting and Drumming" to be technical). The spitting and drumming sound (as the name would suggest) includes a "tsk" noise and then a "whooo" sound that sort of winds up like a motor buzz and actually shakes the turkey's entire body for a few seconds.

That's what I'm trying to emulate.

So the "loop within a loop" can be accomplished with a for loop. You'll just have to figure out how many times you want this for loop to run, and how quickly you want it to run (based on the amount passed to delay()) to be sufficient in emulating what you're trying to do.

I've looked up the "for loop" and it seems like something I'd like to play with (Knight Rider LEDs may soon be coming to my car), but I don't quite see how to use that it my code.

Please forgive my ignorance - I'm very new to this (and have likely bitten off WAY too large of a challenge for a novice such as myself).

JamesR7217:
but I don't quite see how to use that it my code.

The original motor code you posted says "run this code an indefinite number of times"

Wrapping code in a for loop says "run this code a certain number of times"

You want to do the latter, not the former.

Another option would be to use a while loop combined with millis() to run it for a certain number of milliseconds:

unsigned long startTime = millis();
while (millis() - startTime >= 5000UL)
{
  // code in here will run for roughly 5 seconds
}

Alright, well it seems that my code is riddled with errors. Please forgive my ignorance, as stated earlier I'm tragically new to this.

The code I'm attempting to use is this:

#include <pcmRF.h>
#include <TMRpcm.h>

#include <SD.h>                      // need to include the SD library
//#define SD_ChipSelectPin 53  //example uses hardware SS pin 53 on Mega2560
#define SD_ChipSelectPin 10  //using digital pin 4 on arduino nano 328
#include <TMRpcm.h>           //  also need to include this library...

const int sensorPin = 2;           // PIR Sensor is attached to digital pin 2
const int ledPin = 13;             // Built-in LED
const int ledBlinkTime = 500;      // Blink one for half a second while calibrating
int motor = 6;           // the pin that the motor is attached to
int strength = 0;    // how strong the motor is
int fadeAmount = 5;    // how many points to fade the motor by
 
TMRpcm tmrpcm;   // create an object for use in this sketch
char mychar;

// Wait for the seonsor to calibrate (20 - 60 seconds according to datasheet)
// 60 Seconds in milliseconds
const unsigned int calibrationTime = 60000;
 
void setup(){
 
  tmrpcm.speakerPin = 9; //11 on Mega, 9 on Uno, Nano, etc
  
    // declare pin 6 to be an output:
  pinMode(motor, OUTPUT);
 
  Serial.begin(9600);
  if (!SD.begin(SD_ChipSelectPin)) {  // see if the card is present and can be initialized:
    Serial.println("SD fail");  
    return;   // don't do anything more if not
  }
  tmrpcm.play("gobble.wav"); //the sound file "music" will play each time the arduino powers up, or is reset

  Serial.begin(115200);
  
  pinMode(sensorPin, INPUT);
  pinMode(ledPin, OUTPUT);
  
  // We need to wait one minute for the sensor to calibrate
  // Get out of view of the sensor for this duration!
  
  // Blink the LED while calibrating
  for (unsigned int i=0; i<calibrationTime; i+=ledBlinkTime*2) {
    digitalWrite(ledPin, HIGH);
    delay(ledBlinkTime);
    digitalWrite(ledPin, LOW);
    delay(ledBlinkTime);
  }
  
}
 
 
 
void loop(){  
  // Constantly check the state of pin 2
  // If it is HIGH the sensor is detecting motion
  if (digitalRead(sensorPin) == HIGH) {
    // Turn the LED on
    digitalWrite(ledPin, HIGH);
	
    // Play Spitting and Drumming Sound
    tmrpcm.play("spit.wav");
	
    // Wait a second and a half before shaking
    delay(250);
	
	// Start Shaking
	// I somehow need to incorpoate the motor code into this section, but the motor code appears to rely on it's own repeating loop for functionality.
	unsigned long startTime = millis();
    while (millis() - startTime >= 3000UL)
   {
   // code in here will run for roughly 5 seconds
   void loop()  { 
  // set the strength of pin 6:
  analogWrite(motor, strength);    

  // change the strength for next time through the loop:
  strength = strength + fadeAmount;

  // reverse the direction of the fading at the ends of the fade: 
  if (strength == 0 || strength == 255) {
    fadeAmount = -fadeAmount ; 
  }     
  // wait for 30 milliseconds to see the dimming effect    
  delay(30);       
  }
   }
  } else {
    // Turn the LED off
    digitalWrite(ledPin, LOW);
  }
  

}

It refuses to compile giving the following readout:

In file included from turkey_spit_and_drum.ino:1:
C:\Users\James\Documents\Arduino\libraries\TMRpcm/pcmRF.h:14: error: 'boolean' does not name a type
C:\Users\James\Documents\Arduino\libraries\TMRpcm/pcmRF.h:24: error: variable or field 'loadSingleBuffer' declared void
C:\Users\James\Documents\Arduino\libraries\TMRpcm/pcmRF.h:24: error: 'boolean' was not declared in this scope
In file included from turkey_spit_and_drum.ino:2:
C:\Users\James\Documents\Arduino\libraries\TMRpcm/TMRpcm.h:16: error: 'boolean' does not name a type
C:\Users\James\Documents\Arduino\libraries\TMRpcm/TMRpcm.h:17: error: 'boolean' does not name a type
C:\Users\James\Documents\Arduino\libraries\TMRpcm/TMRpcm.h:18: error: 'boolean' does not name a type
C:\Users\James\Documents\Arduino\libraries\TMRpcm/TMRpcm.h:19: error: 'boolean' does not name a type
In file included from turkey_spit_and_drum.ino:4:
C:\Users\James\Documents\Arduino\libraries\pcmRX/pcmRX.h:15: error: expected `)' before 'radio'
C:\Users\James\Documents\Arduino\libraries\pcmRX/pcmRX.h:16: error: 'RF24' has not been declared
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 9
at processing.app.tools.DiscourseFormat.appendFormattedLine(DiscourseFormat.java:194)
at processing.app.tools.DiscourseFormat.show(DiscourseFormat.java:99)
at processing.app.Editor.handleDiscourseCopy(Editor.java:1688)
at processing.app.Editor$TextAreaPopup$4.actionPerformed(Editor.java:2705)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
at javax.swing.AbstractButton.doClick(AbstractButton.java:357)
at javax.swing.plaf.basic.BasicMenuItemUI.doClick(BasicMenuItemUI.java:1225)
at javax.swing.plaf.basic.BasicMenuItemUI$Handler.mouseReleased(BasicMenuItemUI.java:1266)
at java.awt.Component.processMouseEvent(Component.java:6263)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
at java.awt.Component.processEvent(Component.java:6028)
at java.awt.Container.processEvent(Container.java:2041)
at java.awt.Component.dispatchEventImpl(Component.java:4630)
at java.awt.Container.dispatchEventImpl(Container.java:2099)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4238)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
at java.awt.Container.dispatchEventImpl(Container.java:2085)
at java.awt.Component.dispatchEvent(Component.java:4460)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

This makes me think there may be something wrong with my TMRpcm library, which (as I understand it) I need to read the sound files from the microSD card.

If anyone reading this can help me, I'd be extremely appreciative.

Okay, I solved my library problem (turns out that I had incorrectly installed some optional files (intended for radio streaming) that came with my PCM library), and got the code uploaded.

I've had to tweak a few things in order to keep the speaker from just looping the first .25 second of spit.wav forever - but now I'm having a few select problems...

  1. It seems like once the Parralax PIR has been triggered, it never 'untriggers'. (Which is to say that I can set the rig in a completely still room, and once it's triggered, it continues to sound off forever)

  2. I don't seem able to make my motor spin using the code given below.

#include <SD.h>                      // need to include the SD library
//#define SD_ChipSelectPin 53  //example uses hardware SS pin 53 on Mega2560
#define SD_ChipSelectPin 4  //using digital pin 4 on arduino nano 328
#include <TMRpcm.h>           //  also need to include this library...

const int sensorPin = 2;           // PIR Sensor is attached to digital pin 2
const int ledPin = 13;             // Built-in LED
const int ledBlinkTime = 500;      // Blink one for half a second while calibrating
int motor = 6;           // the pin that the motor is attached to
int strength = 0;    // how strong the motor is
int fadeAmount = 5;    // how many points to fade the motor by
 
TMRpcm tmrpcm;   // create an object for use in this sketch
char mychar;

// Wait for the seonsor to calibrate (20 - 60 seconds according to datasheet)
// 60 Seconds in milliseconds
const unsigned int calibrationTime = 60000;
 
void setup(){
 
  tmrpcm.speakerPin = 9; //11 on Mega, 9 on Uno, Nano, etc
  
    // declare pin 6 to be an output:
  pinMode(motor, OUTPUT);
 
  Serial.begin(9600);
  if (!SD.begin(SD_ChipSelectPin)) {  // see if the card is present and can be initialized:
    Serial.println("SD fail");  
    return;   // don't do anything more if not
  }
  tmrpcm.play("gobble.wav"); //the sound file "music" will play each time the arduino powers up, or is reset

  Serial.begin(115200);
  
  pinMode(sensorPin, INPUT);
  pinMode(ledPin, OUTPUT);
  
  // We need to wait one minute for the sensor to calibrate
  // Get out of view of the sensor for this duration!
  
  // Blink the LED while calibrating
  for (unsigned int i=0; i<calibrationTime; i+=ledBlinkTime*2) {
    digitalWrite(ledPin, HIGH);
    delay(ledBlinkTime);
    digitalWrite(ledPin, LOW);
    delay(ledBlinkTime);
  }
  
}
 
 
 
void loop(){  
  // Constantly check the state of pin 2
  // If it is HIGH the sensor is detecting motion
  if (digitalRead(sensorPin) == HIGH) {
    // Turn the LED on
    digitalWrite(ledPin, HIGH);
	
    // Play Spitting and Drumming Sound
    tmrpcm.play("spit.wav");
	
    // Wait a second and a half before shaking
    delay(250);
	
	// Start Shaking
	// I somehow need to incorpoate the motor code into this section, but the motor code appears to rely on it's own repeating loop for functionality.
	unsigned long startTime = millis();
    while (millis() - startTime >= 3000UL)
   {
   // code in here will run for roughly 5 seconds
  // set the strength of pin 6:
  analogWrite(motor, strength);    

  // change the strength for next time through the loop:
  strength = strength + fadeAmount;

  // reverse the direction of the fading at the ends of the fade: 
  if (strength == 0 || strength == 255) {
    fadeAmount = -fadeAmount ; 
  }     
  // wait for 30 milliseconds to see the dimming effect    
  delay(30);       
  }
  delay(30000);
   }
   else {
    // Turn the LED off
    digitalWrite(ledPin, LOW);
  }
  

}