Halloween Forum banner

21 - 40 of 44 Posts

·
Registered
Joined
·
3,324 Posts
Coding in a non-blocking way with lots of tasks does require a change in thinking. I will have to give up at this point as I'm obviously not saying it in a way that you get.
So you're saying you can successfully code my example above with a single core micro? I have to say, I'm very curious because I've never come across anyone that could.
 

·
Registered
Joined
·
210 Posts
So you're saying you can successfully code my example above with a single core micro? I have to say, I'm very curious because I've never come across anyone that could.
I seem to remember past threads where people have successfully done it with Arduino's before. I remember that the people saying it was possible did also say you had to rethink the way you address the issue. There may already be libraries available to handle this sort of thing. When I was looking into the issue I was addressing lighting, but the theory is probably the same no matter what your goal is. Instead of blocking the processor by delaying you have to rethink what your actual goal is. You are only allowed one process so the last thing you want to do is stop the processor, you need it to run full speed.

Maybe it was a theory called protothreading?

 

·
Registered
Joined
·
3,324 Posts
I totally understand the theory, not disputing that. I'm just saying that everything has limits and I don't see how it could function for this particular application. I'm not saying it's impossible, just saying I've never seen anyone successfully do it.
 

·
Registered
Joined
·
45 Posts
Not sure how to post this but I found this on the net a few years ago.
The program moves many servos randomly. I use the Nano for this. You can adjust limits and speeds individually. I didn't write it but it works for me.

You will need to download
ServoEaser.cpp
ServoEaser.h

If this isn't supposed to be here please remove it.
Thanks and good luck.


// NEONATAL ANIMATRONIC NEWBORN OFFSPRING
//=======================================================================//
//====================--- I N N E R B R E E D F X ---====================//
// Project; NANO Baby (Base Code) //
// Description: http://www.innerbreed.co.uk //
// Version: V1.0 //
// Start Date: 24/12/2017 //
// Last Edit Date: 11/01/2018 //
// Developer/s: Jonny Poole (aka Innerbreed) //
// //
// FEATURES: Servo Easing applied for joint compliance. //
//=======================================================================//
//=======================================================================//

// Engineer / Developers notes:
// ServoEaser library for Arduino
// ==============================
// 2011, TeamPneumo, Tod E. Kurt, http://todbot.com/blog/
// ServoEaser is an Arduino library makes doing animation-style movements with
// servos easier.

// Features:
// - Supports directly telling a servo to ease to a position over a duration
// - Supports playing of previously-defined "move lists"
// - User-specified easing functions (defaults to easeInOutCubic), see Easing lib
// - User-specified "servo arrived" function for async callback when movement done
// - Supports both integer angle movement and a "microseconds" mode for fine-grained control with float-ing point angles

// License
// Copyright © 2018 by Jonny Poole. All right reserved.

//----------------
// HEADER FILES
#include <Servo.h>
#include "ServoEaser.h"

//----------------
// SERVO NAMES (Defined) (15 Servos in total)
Servo Blink; // Right and Left run together 2x(hs65hb)
Servo Jaw; // 1x(hs65hb)
Servo Lip; // 1x(hs65hb)
Servo Neck_Tilt_Left; // Combines with (Neck_Tilt_Right) to lift head 1x(hs65mg)
Servo Neck_Tilt_Right; // Combines with (Neck_Tilt_Left) to lift head 1x(hs65mg)
Servo Head_Rotate; // 1x(hs645mg)
Servo Left_Elbow_ShoulderRoll; // 1x(hs311) and 1x(hs65hb)
Servo Right_Elbow_ShoulderRoll; // 1x(hs311) and 1x(hs65hb)
Servo Right_ShoulderUp; // 1x(hs65hb)
Servo Left_ShoulderUp; // 1x(hs65hb)
Servo Legs; // Right and left run together 2x(hs311)

//----------------
// SERVO EASER (Defined)
ServoEaser BlinkEaser; // Set up ServoEaser for each servo
ServoEaser JawEaser;
ServoEaser LipEaser;
ServoEaser Neck_Tilt_LeftEaser;
ServoEaser Neck_Tilt_RightEaser;
ServoEaser Head_RotateEaser;
ServoEaser Left_Elbow_ShoulderRollEaser;
ServoEaser Right_Elbow_ShoulderRollEaser;
ServoEaser Right_ShoulderUpEaser;
ServoEaser Left_ShoulderUpEaser;
ServoEaser LegsEaser;

//----------------
// INTERNAL CLOCK
int servoFrameMillis = 10; // Minimum time in m/s between servo updates
unsigned long lastMillis;

//---------------------------------------------------------------
// INITIAL SET UP
void setup(){
// Initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);

// ATTACHED SERVOS ServoName.attach(Pin);
Blink.attach(2);
Jaw.attach(3);
Lip.attach(4);
Neck_Tilt_Left.attach(5);
Neck_Tilt_Right.attach(6);
Head_Rotate.attach(7);
Left_Elbow_ShoulderRoll.attach(8);
Right_Elbow_ShoulderRoll.attach(9);
Right_ShoulderUp.attach(10);
Left_ShoulderUp.attach(11);
Legs.attach(12);

// Initiate blink upon power-up to show that the mech is active
// Active LED for engineers attention
Blink.write(115); // Closed
digitalWrite(LED_BUILTIN, LOW); // turn the LED off
delay(120);
Blink.write(80); // Opened
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on
delay(750);
Blink.write(115); // Closed
digitalWrite(LED_BUILTIN, LOW); // turn the LED off
delay(120);
Blink.write(80); // Opened
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on
delay(500);
Blink.write(115); // Closed
digitalWrite(LED_BUILTIN, LOW); // turn the LED off

//----------------
// CALL EASING PARAMETERS
BlinkEaser.begin( Blink, servoFrameMillis); // Begin servo moves
JawEaser.begin( Jaw, servoFrameMillis);
LipEaser.begin( Lip, servoFrameMillis);
Neck_Tilt_LeftEaser.begin( Neck_Tilt_Left, servoFrameMillis);
Neck_Tilt_RightEaser.begin( Neck_Tilt_Right, servoFrameMillis);
Head_RotateEaser.begin( Head_Rotate, servoFrameMillis);
Left_Elbow_ShoulderRollEaser.begin( Left_Elbow_ShoulderRoll, servoFrameMillis);
Right_Elbow_ShoulderRollEaser.begin( Right_Elbow_ShoulderRoll, servoFrameMillis);
Right_ShoulderUpEaser.begin( Right_ShoulderUp, servoFrameMillis);
Left_ShoulderUpEaser.begin( Left_ShoulderUp, servoFrameMillis);
LegsEaser.begin( Legs, servoFrameMillis);

BlinkEaser.useMicroseconds( true ); // Start timer
JawEaser.useMicroseconds( true );
LipEaser.useMicroseconds( true );
Neck_Tilt_LeftEaser.useMicroseconds( true );
Neck_Tilt_RightEaser.useMicroseconds( true );
Head_RotateEaser.useMicroseconds( true );
Left_Elbow_ShoulderRollEaser.useMicroseconds( true );
Right_Elbow_ShoulderRollEaser.useMicroseconds( true );
Right_ShoulderUpEaser.useMicroseconds( true );
Left_ShoulderUpEaser.useMicroseconds( true );
LegsEaser.useMicroseconds( true );

BlinkEaser.easeTo( 90, 5000); // Eases to given random angle and speed
JawEaser.easeTo( 90, 5000);
LipEaser.easeTo( 90, 5000);
Neck_Tilt_LeftEaser.easeTo( 90, 5000);
Neck_Tilt_RightEaser.easeTo( 90, 5000);
Head_RotateEaser.easeTo( 90, 5000);
Left_Elbow_ShoulderRollEaser.easeTo( 90, 5000);
Right_Elbow_ShoulderRollEaser.easeTo( 90, 5000);
Right_ShoulderUpEaser.easeTo( 90, 5000);
Left_ShoulderUpEaser.easeTo( 90, 5000);
LegsEaser.easeTo( 90, 5000);
}

//---------------------------------------------------------------
// MAIN CODE
void loop()
{
// UPDATE SERVO POSITION
BlinkEaser.update();
JawEaser.update();
LipEaser.update();
Neck_Tilt_LeftEaser.update();
Neck_Tilt_RightEaser.update();
Head_RotateEaser.update();
Left_Elbow_ShoulderRollEaser.update();
Right_Elbow_ShoulderRollEaser.update();
Right_ShoulderUpEaser.update();
Left_ShoulderUpEaser.update();
LegsEaser.update();

ALIVE();
}

//----------------
void ALIVE() // ITS MAGIC TIME
{

if( BlinkEaser.hasArrived() ) { // BLINK EYES
lastMillis = millis(); // Timer count
int angle = random(80,120); // Servo operating angle: 0 - 180
int duration = random(100,2000); // Speed of rotation min/max
BlinkEaser.easeTo( angle, duration ); // Eases to given random angle and speed
}
if( JawEaser.hasArrived() ) { // JAW
lastMillis = millis();
int angle = random(50,110);
int duration = random(200,3000);
JawEaser.easeTo( angle, duration );
}
if( LipEaser.hasArrived() ) { // LIP
lastMillis = millis();
int angle = random(60,90);
int duration = random(200,1000);
LipEaser.easeTo( angle, duration );
}
if( Neck_Tilt_LeftEaser.hasArrived() ) { // NECK TILT LEFT
lastMillis = millis();
int angle = random(60,90);
int duration = random(200,1500);
Neck_Tilt_LeftEaser.easeTo( angle, duration );
}
if( Neck_Tilt_RightEaser.hasArrived() ) { // NECK TILT RIGHT
lastMillis = millis();
int angle = random(90,110);
int duration = random(200,1500);
Neck_Tilt_RightEaser.easeTo( angle, duration );
}
if( Head_RotateEaser.hasArrived() ) { // HEAD ROTATE
lastMillis = millis();
int angle = random(30, 150);
int duration = random(800,3500);
Head_RotateEaser.easeTo( angle, duration );
}
if( Left_Elbow_ShoulderRollEaser.hasArrived() ) { // SHOULDER ROLL and ELBOW LEFT
lastMillis = millis();
int angle = random(70, 90);
int duration = random(200,2000);
Left_Elbow_ShoulderRollEaser.easeTo( angle, duration );
}
if( Right_Elbow_ShoulderRollEaser.hasArrived() ) {// SHOULDER ROLL and ELBOW RIGHT
lastMillis = millis();
int angle = random(80, 105);
int duration = random(200,2000);
Right_Elbow_ShoulderRollEaser.easeTo( angle, duration );
}
if( Right_ShoulderUpEaser.hasArrived() ) { // SHOULDER UP RIGHT
lastMillis = millis();
int angle = random(80, 140);
int duration = random(200,1500);
Right_ShoulderUpEaser.easeTo( angle, duration );
}
if( Left_ShoulderUpEaser.hasArrived() ) { // SHOULDER UP LEFT
lastMillis = millis();
int angle = random(40, 110);
int duration = random(200,1500);
Left_ShoulderUpEaser.easeTo( angle, duration );
}
if( LegsEaser.hasArrived() ) { // LEGS
lastMillis = millis();
int angle = random(180);
int duration = random(200,5000);
LegsEaser.easeTo( angle, duration );
}
}

// License
// Copyright © 2018 by Jonny Poole. All right reserved.
 

·
Registered
Joined
·
3,324 Posts
That's impressive for sure but I don't think it will apply to an Arduino that is configured as a "Jawduino". It has to continually monitor the audio input for jaw sync.
 

·
Registered
Joined
·
3,324 Posts
I tried to add different items to the "Jawduino" code but another Arduino is the best I could come up with.
Yep, that's what I've been saying all along. Arduinos are so cheap (and small) not a big deal to add one for each servo in a 3-axis skull.
 

·
Registered
Joined
·
134 Posts
J-Man, I think you're underestimating what a microprocessor can do, and overestimating what servo control requires. Standard servo runs a 20ms cycle (most will work just fine on a longer cycle). In order to send a control signal the processor has to set the output high once and set the output low once, during that 20ms cycle. Arduinos commonly run at 8MHz. 8 million cycles per second. 160K instructions for each 20ms servo period. That's a lot of processing available.
It is also possible to use arduino's PWM output to control servos. the PWM function uses separate counters that don't involve the regular processor, so all you need to do is set the position whenever you want it to change.
I regularly use little attiny85s (8 pin chips programmed with arduino libraries) to run multiple servos, leds, displays, and read inputs. It's not hard.
 

·
Registered
Joined
·
229 Posts
You also don't have to sample the audio continuously as in every microsecond. There's heaps of processor time (cycles) available to sample triggers and audio as well as update servos, etc. Coding like that does need a shift in thinking. Cobbling multiple Arduino sketches together as one program will not usually work. You need to think about events and flags as well as using interrupts to get regular stuff done in a seemingly (to us slow humans) simultaneous way.
 

·
Registered
Joined
·
3,324 Posts
J-Man, I think you're underestimating what a microprocessor can do, and overestimating what servo control requires. Standard servo runs a 20ms cycle (most will work just fine on a longer cycle). In order to send a control signal the processor has to set the output high once and set the output low once, during that 20ms cycle. Arduinos commonly run at 8MHz. 8 million cycles per second. 160K instructions for each 20ms servo period. That's a lot of processing available.
It is also possible to use arduino's PWM output to control servos. the PWM function uses separate counters that don't involve the regular processor, so all you need to do is set the position whenever you want it to change.
I regularly use little attiny85s (8 pin chips programmed with arduino libraries) to run multiple servos, leds, displays, and read inputs. It's not hard.
With all due respect, I program servo control using PIC's all the time, I don't need any schooling on how it works. Am I a guru programmer? No, certainly not but I do OK for my needs.
 

·
Registered
Joined
·
134 Posts
J-Man, maybe you're doing OK for your needs, but for the others here seeking advice I feel like I need to offer a counter point to your suggestion to use one arduino per servo. The amount of effort needed to set up communication between multiple arduinos in order to coordinate is way more than just driving multiple servos from one arduino.
And since you're challenging people to control more than one servo with a single microprocessor...
Here's the standard arduino servo library: https://playground.arduino.cc/ComponentLib/Servo/ "The Servo library supports up to 12 motors on most Arduino boards..." using one of the timers, so there's no processor time beyond setting the desired values.
If 12 isn't enough (or timers are being used for something else) software-servo libraries can essentially run servos off every I/O pin: https://playground.arduino.cc/ComponentLib/Servo/
 

·
Registered
Joined
·
229 Posts
The one thing I think we all agree on is that there's always more to learn when it comes to electronics and programming. Even though I've been designing electronics and writing code for about 35 years, I still have those "oh wow, that's a better way of doing that" moments. Sometimes I'll code something up, then after a fresh look at it come up with a much more elegant and extendable solution. :)
 

·
Registered
Joined
·
3,324 Posts
J-Man, maybe you're doing OK for your needs, but for the others here seeking advice I feel like I need to offer a counter point to your suggestion to use one arduino per servo. The amount of effort needed to set up communication between multiple arduinos in order to coordinate is way more than just driving multiple servos from one arduino.
And since you're challenging people to control more than one servo with a single microprocessor...
Here's the standard arduino servo library: https://playground.arduino.cc/ComponentLib/Servo/ "The Servo library supports up to 12 motors on most Arduino boards..." using one of the timers, so there's no processor time beyond setting the desired values.
If 12 isn't enough (or timers are being used for something else) software-servo libraries can essentially run servos off every I/O pin: https://playground.arduino.cc/ComponentLib/Servo/
This conversation has gotten way off track. The original poster (Brianaala) asked for working code to run a random 3-axis "Jawduino" skull. No one has provided that. Maybe it's possible, maybe not. Until someone actually provides him with working code for this, I am officially done with this topic.
 

·
Registered
Joined
·
134 Posts
David_AVD, thanks for the perspective. Always more to learn.

Brianaala, it's hard to offer specific advice without more information. While I could look at the Jawduino code, it sounds like you've altered it significantly so I can't guess what it looks like now. Could you elaborate on what you're goal is? maybe share what you're doing in the arduino loop method?
 

·
Registered
Joined
·
40 Posts
Discussion Starter #36
Hi everyone! Wow this has gotten a lot of attention and I really appreciate your help! I have been out of town which is why I haven't been able to respond. I will post the code when I get home. If I could get the code to run 2 or more extra servos in conjunction (or at least seemingly at the same time) that would be perfect! I agree that even if the servos are taking turns in MS it will convey the illusion just fine! Again I really thank you all for the input and support!
 

·
Registered
Joined
·
40 Posts
Discussion Starter #37
What I was doing in this is trying to get the code to run just one additional random head turn servo (seemingly) simultaneously with the jaw movement. OK here is the code that I have so far:
Code:
//*****************************************************************************
//      Hard settings
//********************************************************************************
int trackDelay = 1000; //1000 is one second, 5000 is five seconds, etc. this is the minimum delay between retrigger of the prop.
int trackCount = 002; //this should be the total number of tracks in folder 01 and must include any preceding zeros to three places i.e. 2 tracks is 002, 5 tracks is 005, 12 tracks is 012
#include <VarSpeedServo.h> //this library should allow servos to operate at variable speeds
#include "SoftwareSerial.h" //I think this allows the serial monitor
#include "DFRobotDFPlayerMini.h" //library to operate the mp3 player
VarSpeedServo jaw;//Jaw servo
VarSpeedServo turn;//Head turn servo
SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;
int turnpos; //The position of the head turn servo
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;  //the value is a number of milliseconds
int ledPin = 5;
//**********************************************************************************
//                  PIR Sensor Setup
//**************************************************************************

int calibrationTime = 1;       // The time we give the sensor to calibrate (10-60 secs according to the datasheet) total time in seconds is 2*calibrationTime
int pirPin = 2;                 // The PIR sensor's output
long unsigned int lowIn;        // The time when the sensor outputs a low impulse

long unsigned int pause = 5000;  // 5 seconds the sensor has to be low
                                 // before we assume all motion has stopped
boolean lockLow = true; //Not sure what this does
boolean takeLowTime; //Not sure what this does

//**********************************************************************************
//                  MP3 Setup
//***********************************************************************
int audioVal;//read the volume of audio input from VU
int mode = 1;
int busy;//mp3 busy pin
int track = 001;//starts at track #1
//*************************************************************************
//                  PIR/MP3 Function Setup
//***************************************************************
    

//***************************************************************************
void setup()
{
  //*****************************************************************************
 //           PIR Sensor Calibration
 //*************************************************************
 void calibrateTime();
 pinMode(pirPin, INPUT);        // Digital Pin 3
 digitalWrite(pirPin, LOW);      // Turn off internal pull up resistor
  // Give the sensor some time to calibrate
  calibrateTime();               // 60 seconds calibration time
            
//******************************************************************************
  //          Jaw Servo/MP3 Play
//**************************************************************
  jaw.attach(6);  //Attaches pin 6 to jaw servo
  turn.attach(5); //Attach pin 5 to turn Servo
  mySoftwareSerial.begin(9600);// start serial port at 9600 bps:
 
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
 
  if (!myDFPlayer.begin(mySoftwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("DFPlayer Mini online."));
 
  myDFPlayer.setTimeOut(500); //Set serial communication time out 500ms
 
  //----Set volume----
  myDFPlayer.volume(27);  //Set volume value (0~30).
    
  //----Set different EQ----
 myDFPlayer.EQ(DFPLAYER_EQ_NORMAL);
  
  //----Set device we use SD as default----

  myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD);

  //----Read information----
  Serial.print("MP3 Status: ");
  Serial.println(myDFPlayer.readState()); //read mp3 state
  Serial.print("Volume: ");
  Serial.println(myDFPlayer.readVolume()); //read current volume
  Serial.print("EQ: ");
  Serial.println(myDFPlayer.readEQ()); //read EQ setting
  Serial.print("Total File Count: ");
  Serial.println(myDFPlayer.readFileCounts()); //read all file counts in SD card
  Serial.print("Current File: ");
  Serial.println(myDFPlayer.readCurrentFileNumber()); //read current play file number
  Serial.print("File count in folder:(folder 1 specified) ");
  Serial.println(myDFPlayer.readFileCountsInFolder(01)); //read file counts in folder SD:/01
  myDFPlayer.play();  //Play the first mp3
   startMillis = millis();  //initial start time
}

void loop()
{
 
//********************************************************
 //         MP3 Servo Motion
// *******************************************************
  
 audioVal = 300;
  if(analogRead(1) < 341) audioVal += 333;//if A1 recieves signal open jaw 30
  if(analogRead(2) < 341) audioVal += 333;//if A2 recieves signal open jaw 60
  if(analogRead(3) < 341) audioVal += 333;//if A3 recieves signal open jaw 90

 if(audioVal > 0)
    {
    jaw.writeMicroseconds(audioVal);//move Jaw with sound
        }
  //{turnpos = random(120);//generate random value for turn servo
  //     turn.write(turnpos,40); //move turn servo at particular speed
  //  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  //if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  //{
    digitalWrite(turnpos, !digitalRead(turnpos));  //if so, change the state of the LED.  Uses a neat trick to change the state
    startMillis = currentMillis;  //IMPORTANT to save the start time of the current LED state.
  //} 
   //   }
  mp3();
}

void mp3()
{
  //**********************************************************************
//          PIR SENSOR START 
//**********************************************************************   
 
    
busy=analogRead(4);
 
           if (analogRead(4) <= 300) //busy pin from mp3 player ignore sensor
      {
        digitalWrite(ledPin, HIGH);
        Serial.print ("Busy: ");
        Serial.println (busy);
      }
     else if (analogRead(4) >= 301)//if not busy then:
        {
          digitalWrite(ledPin, LOW);
           mode= mode+1;
           Serial.print("Mode: ");
           Serial.println(mode);
          // delay(15);
           if (mode==1) //mp3 mode is 1 then:
           {track=random(001,trackCount); //play random track
           myDFPlayer.playFolder(01, track);}
           if (mode==2)
           {delay(trackDelay);}//probably have to change this to millis
          // if (mode==3)
        //   {mode=0;}
        }
 /* if (myDFPlayer.available())
      {
       printDetail(myDFPlayer.readType(), myDFPlayer.read()); //Print the detail message from DFPlayer to handle different errors and states.
      }*/
      if((digitalRead(pirPin) == HIGH) and (analogRead(4) > 300))    // The PIR saw something & MP3 player isn't playing
     {   
       if(lockLow)                      // Starts True
       { 
         lockLow = false;               // Makes sure we wait for a transition to LOW before any further output is made:         
         //delay(50);
       }         
       takeLowTime = true;              // No default
      
     // stopMp3();                       // Stop the MP3 player                 
//      playTrack(1);                    // Play one Random Track
       myDFPlayer.next();  //Play the next mp3
       //for(int i = 0; i < 4; i++)      // Wait 4 seconds For MP3 to start.
       {
         delay(1000);
       }

      //   while(analogRead(4) <= 300)                 // Wait for MP3 player to finish current track
      //   {
      //    if((digitalRead(pirPin) == HIGH))  // Visualize sensor busyPin or pirPin
         //  {
         //    digitalWrite(ledPin, HIGH);
            

      //    }
       //    else
           //{
          //   digitalWrite(ledPin, LOW);
            
         //  }
       //    delay(50);               
      //   }

      stopMp3();                       // Stop the MP3 player 
     }

     if(digitalRead(pirPin) == LOW)
     {       
  //     digitalWrite(ledPin, LOW);  //the led visualizes the sensors output pin state
      
       if(takeLowTime)             // If PIR was just High
       {
         lowIn = millis();          // Save the time of the transition from High to LOW
         takeLowTime = false;       // Make sure this is only done at the start of a LOW phase
       }
      
       //if the sensor is low for more than the given pause,
       //we assume that no more motion is going to happen
       if(!lockLow && millis() - lowIn > pause)
       { 
           //makes sure this block of code is only executed again after
           //a new motion sequence has been detected
           lockLow = true;                       
          // delay(50);
          
       }
     }
    
}
//********************************************************
    //          Calibrate the PIR
// *******************************************************

  void calibrateTime()
   {
    //  for(int i = 0; i < calibrationTime; i++)
    
      //{
      //  digitalWrite(ledPin, HIGH);
      //  delay(500);                  // wait for a second
     //   digitalWrite(ledPin, LOW);
     //   delay(500);                  // wait for a second
     // }
      
    //  digitalWrite(ledPin, HIGH);
   }
void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}



// *******************************************************
//          STOP  play
// *******************************************************
void stopMp3()
{
    Serial.write(0xEF); 
    delay(10);
}
 

·
Registered
Joined
·
134 Posts
I'd suggest spending a bit of time to clean up your code so it's easier for you to follow. Particularly, the PIR calibration isn't doing anything. And the code to handle reading the audio signal and writing the jaw servo was clearer as a separate function. I'm also guessing at which parts you've commented out permanently vs those you're trying to debug. It looks like the old servo library was taking degrees as input, and the new one is either degrees or microseconds. Note that valid range for servos is around 500-2500, and your range is 300-1299 for the jaw. And looks like you're using degrees for the neck. Switch the jaw back to degrees to make things less confusing?
But I'm guessing the main problem you're seeing with the neck control is you're changing the the position everytime to you go through the loop, not waiting for it to reach the requested position.
also "digitalWrite(turnpos, !digitalRead(turnpos))" when turnpos is a random number is flipping the state on some random pin, which is likely to cause you issues.

Anyway, here's some psuedocode I'd suggest as a structure for the loop method. I haven't used DFPlay, so I'm guessing at things there.

void loop() {
audio_updates(); // read the audio levels. do this every time.
action(); // update the jaw servo. do this every time.
handle_mp3(); // check PIR and mp3 status
handle_neck_servo(); // update neck servo as needed
}

and psuedocode for those new functions:

void handle_mp3() {
if (!digitalRead(busy_pin)) {
return; // already playing, nothing more to do
}
if (digitalRead(pir_pin)) { // if motion detected
dfPlayer.play(random(track_count)); // start a random track
}
}

void handle_neck_servo() {
if (neck.isMoving()) {
return; // don't set new position while still moving to previously set position
}
// pick a reasonable random angle and a random speed. You can extend this to be more complex.
neck.write(random(60, 120), random(10,40));
}
 

·
Registered
Joined
·
40 Posts
Discussion Starter #40
Wow you folks are awesome! Clearly I'm a novice at this and you're absolutely correct; I need to clean it up, I just didn't know what I could take out without adverse effects. I will go over this and try to make the changes that you suggest! Thanks again!
 
21 - 40 of 44 Posts
Top