Nano's now only displaying "Se", code worked fine at first

This is my first time ever posting here, so please forgive me if this is the wrong category or if I made another mistake with this post.

I hope that somebody can help me understand why my code/program isn't working, while it worked perfectly fine before adding the 33rd entry to the switch case?
(undoing that, didn't seem to help either)

The project:
I thought it would be a fun idea to built my own little robot, with plans from the internet.
It's a little robot with 3 sg90g micro servo's, a piëzo buzzer and a hc-sr04 ultrasound sensor.
The Arduino is an Arduino nano. I tried 3 different ones: one nano of unknown origin (had it laying around), one (clone) ordered from Amazon which says Az-Delivery on the bottom and an arduino (clone?) ordered from Aliexpress.
I have chosen the settings to use the processor: Atmega328P (Old Bootloader)
Before attempting this I tried some very simple programming in Unity in C#, but I never wrote anything before in C for Arduino.
The code therefore is unoptimized, probably written wrong and I haven't really used any arrays eventhough it probably can use those. I really just stuck to writing code as simple as possible to get it to work with the idea to maybe optimize later when I have a running code and some more understanding of C.

The problem:
When I wrote this, I did so piece-by-piece and I checked functionality of all functions before writing another.
All functions seem to work when it's just a single function and added to Setup() or Loop().
I also briefly got everything to work (at least a little) in the "switch" loop, as seen in the code.
However, it completely stopped working after adding another case to the switch.
The Arduino now only displays "Se" on the serial monitor and stops.
This is also the case when nothing else is hooked onto the Arduino, even the one I just bought.

Can someone please explain what I'm doing wrong? (Except the way I've written the code, I guess that must look horrible :sweat_smile:)
Is it the "switch" I added to the loop?
Is there some sort of mistake I made in the code? (it does not give any errors)
Or is it because they might be cloned arduino's? (then I'll never buy another of those again)

PS: I've seen that "Delay()" is a bit frowned upon, but I didn't know of a different way to "wait" / "halt code continuation" for the amount of time I used in that function.

//--------------------------- LIBRARIES TO USE ---------------------------//
#include <Servo.h>    // Arduino library for servo's.
#include <math.h>     // Standard C library for mathematic operations.
#include "pitches.h"  // Arduino library to use a piezo buzzer.

//--------------------------- IMPORTANT VARIABLES ---------------------------//
// Servo's and assigned names
Servo baseServo;
Servo neckServo;
Servo headServo;

// Speed and delay settings
int delayBetweenSweepMoves = 500;  // Delay between initial sweeping move orders.
int intitialMovementSpeed = 10;    // The general delay between movements when facing a set direction. Higher numbers will make movement increment slower; delays movement increments in miliseconds.

// Ultrasonic variables
#define echoPin 6     // Echo pin
#define triggerPin 5  // Trigger pin

//Buzzer
#define buzzerPin 7  // Buzzer pin

// Bools to keep track of reactions, sweeping moves and idles.
bool hasReacted;  // Bool to break out of a while loop when reading changes.


// Array that can be used to define random actions and giving the illusion of a 'pet' with a mind of it's own.
//int sweepingMoves[] = {};
// int idleMoves[] = {};
//We can split the actions up in 2 different ararys and then make it so that we only sweep on one iteration and do an idle on the next.
//But for the added random factor we chose not to do so.
int actions[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
int chosenAction;

// Variables for storing distances at locations.
// This is used as a form of 'mapping' the area to interact with changes.
long lowPos0;  // Lower position at 0°.
long lowPos45;
long lowPos90;
long lowPos135;
long lowPos180;  // Lower position at 180°.
long highPos0;   // Position 45° upwards and at 0° relative to the base.
long highPos45;
long highPos90;
long highPos135;
long highPos180;  // position 45° upwards and at 180° relative to the base.
long topPos;      // Position straight above


//--------------------------- SETUP FUNCTION ---------------------------//
void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.flush();
  baseServo.attach(2);
  neckServo.attach(4);
  headServo.attach(3);

  Serial.setTimeout(50);  // To ensure the Arduino doesn't read/wait for the serial too long
  Serial.println("Serial communication started.");

  // The initial servo positions
  baseServo.write(90);
  neckServo.write(90);
  headServo.write(90);

  // The ultrasonic sensor setup
  pinMode(triggerPin, OUTPUT);
  pinMode(echoPin, INPUT);

  // Reaction bool is set to 'false'. Since it hasn't been able to react yet due to just booting up.
  hasReacted = false;

  // Initial mapping distances
  faceLow90(25);
  DoFirstMappingSweep();
  faceLow90(10);
  delay(5000);  // Wait 5 seconds before starting an action.
}
//--------------------------- LOOP FUNCTION ---------------------------//
void loop() {
  // put your main code here, to run repeatedly:
  chosenAction = random(0, 33);
  switch (chosenAction) {
    case 0:
      Serial.println("CasualSweepLow1");
      CasualSweepLow1();
      break;
    case 1:
      Serial.println("CasualSweepLow2");
      CasualSweepLow2();
      break;
    case 2:
      Serial.println("CasualSweepLow3");
      CasualSweepLow3();
      break;
    case 3:
      Serial.println("CasualSweepLow4");
      CasualSweepLow4();
      break;
    case 4:
      Serial.println("CasualSweepLow5");
      CasualSweepLow5();
      break;
    case 5:
      Serial.println("CasualSweepHigh1");
      CasualSweepHigh1();
      break;
    case 6:
      Serial.println("CasualSweepHigh2");
      CasualSweepHigh2();
      break;
    case 7:
      Serial.println("CasualSweepHigh3");
      CasualSweepHigh3();
      break;
    case 8:
      Serial.println("CasualSweepHigh4");
      CasualSweepHigh4();
      break;
    case 9:
      Serial.println("CasualSweepHigh5");
      CasualSweepHigh5();
      break;
    case 10:
      Serial.println("CasualSweepTop");
      CasualSweepTop();
      break;
    case 11:
      Serial.println("CasualSweepMixed1");
      CasualSweepMixed1();
      break;
    case 12:
      Serial.println("CasualSweepMixed2");
      CasualSweepMixed2();
      break;
    case 13:
      Serial.println("CasualSweepMixed3");
      CasualSweepMixed3();
      break;
    case 14:
      Serial.println("CasualSweepMixed4");
      CasualSweepMixed4();
      break;
    case 15:
      Serial.println("CasualSweepMixed5");
      CasualSweepMixed5();
      break;
    case 16:
      Serial.println("CasualSweepMixed6");
      CasualSweepMixed6();
      break;
    case 17:
      Serial.println("Dance1");
      Dance1();
      break;
    case 18:
      Serial.println("Dance2");
      Dance2();
      break;
    case 19:
      Serial.println("Headbang");
      Headbang();
      break;
    case 20:
      Serial.println("SwayHead1");
      SwayHead1();
      break;
    case 21:
      Serial.println("SwayHead2");
      SwayHead2();
      break;
    case 22:
      Serial.println("SwayHead3");
      SwayHead3();
      break;
    case 23:
      Serial.println("SwayHead4");
      SwayHead4();
      break;
    case 24:
      Serial.println("SwayHead5");
      SwayHead5();
      break;
    case 25:
      Serial.println("SitUpIdle");
      SitUpIdle();
      break;
    case 26:
      Serial.println("PlayYankeeDoodle");
      PlayYankeeDoodle();
      break;
    case 27:
      Serial.println("PlayAuClaireDeLaLune");
      PlayAuClaireDeLaLune();
      break;
    case 28:
      Serial.println("Speak1");
      Speak1();
      break;
    case 29:
      Serial.println("Speak2");
      Speak2();
      break;
    case 30:
      Serial.println("Speak3");
      Speak3();
      break;
    case 31:
      Serial.println("Speak4");
      Speak4();
      break;
    case 32:
      Serial.println("PlayTwinkleTwinkleLittleStar");
      PlayTwinkleTwinkleLittleStar();
      break;
  }

  delay(random(5001, 30001));  // To make sure that your personal buddy doesn't seem like a child that ate too much sugar!
                               //It can chill for a few seconds (between 5 en 30) before performing the next action.
}


//--------------------------- FUNCTIONS ---------------------------//

//Measure distance to objects in front of the sensor.
int MeasureDistance(int EchoPin, int TriggerPin) {  // Calculate distance in cm

  long duration, distance;
  digitalWrite(TriggerPin, LOW);
  delayMicroseconds(2);

  digitalWrite(TriggerPin, HIGH);
  delayMicroseconds(10);

  digitalWrite(TriggerPin, LOW);
  duration = pulseIn(EchoPin, HIGH);

  distance = (duration / 2) * 0.0344;
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.print(" cm");
  return distance;
}

// Actual movement function to send servo's to the desired configuration.
void MoveTo(Servo movingServo, int positionInDegrees, int speedDelay) {
  bool haveToMove = true;
  int currentPos = movingServo.read();
  int targetPos = positionInDegrees;
  int newPos;

  while (haveToMove) {
    if (currentPos < targetPos) {
      movingServo.write(currentPos++);
      delay(speedDelay);
    }

    else if (currentPos > targetPos) {
      movingServo.write(currentPos--);
      delay(speedDelay);
    } else  // Then the target position and current position are the same
    {
      haveToMove = false;
    }
  }
}

int CalculateDistanceDifference(int distance1, int distance2) {
  int difference;
  difference = abs(distance1 - distance2);
  return difference;
}



float GetRandomDuration(int RandomAmount) {
  for (int i = 0; i < RandomAmount; i++) {
    return random(2, 8);
  }
}

// React to change
void MeasureAndReact(long facingPosition) {
  int currentMeasuredDistance;
  int distanceDifference;
  currentMeasuredDistance = MeasureDistance(echoPin, triggerPin);
  distanceDifference = CalculateDistanceDifference(currentMeasuredDistance, facingPosition);
  Serial.println(distanceDifference);
  if (distanceDifference > 10 && distanceDifference < 200 && currentMeasuredDistance > 10) {
    ActCurious();
    hasReacted = true;
    Serial.println("Has reacted");
  } else if (distanceDifference > 50 || currentMeasuredDistance < 10 && distanceDifference > 1) {
    ActStartled();
    hasReacted = true;
    Serial.println("Has reacted");
  } else if (distanceDifference > 100 && currentMeasuredDistance < 30 && currentMeasuredDistance > 1) {
    ActStartled();
    hasReacted = true;
    Serial.println("Has reacted");
  } else if (distanceDifference > 100 && currentMeasuredDistance < 200 && currentMeasuredDistance > 10) {
    ActCurious();
    hasReacted = true;
    Serial.println("Has reacted");
  } else {
    hasReacted = false;
    Serial.println("Has not reacted");
  }
}

//--------------------------- Reactions ---------------------------//
void ActCurious() {
  MoveTo(headServo, 45, 20);
  MoveTo(headServo, 135, 20);
  SpeakCurious();
  MoveTo(headServo, 45, 20);
  delay(1000);
  MoveTo(headServo, 90, 30);
}

void ActStartled() {
  MoveTo(headServo, 45, 2);
  MoveTo(neckServo, 35, 5);
  SpeakStartled1();
  MoveTo(neckServo, 90, 5);
  MoveTo(neckServo, 35, 5);
  SpeakStartled2();
  MoveTo(neckServo, 90, 5);
  MoveTo(headServo, 135, 2);
  MoveTo(neckServo, 35, 5);
  SpeakStartled2();
  MoveTo(neckServo, 90, 5);
  MoveTo(neckServo, 35, 5);
  SpeakStartled1();
  noTone(buzzerPin);  // Just in case. I had an instance where the buzzer kept on going for a little while.
  MoveTo(neckServo, 90, 5);
  MoveTo(headServo, 45, 2);
  delay(500);
  MoveTo(headServo, 90, 10);
}



//--------------------------- Personal buddy Behaviours ---------------------------//
//--------------------------- Sweeps ---------------------------//
// Sweeping behaviors. Varrying from pretty thorough to only measuring 1 or 2 points.
// First sweep to map everything
void DoFirstMappingSweep() {
  faceLow0(intitialMovementSpeed);
  lowPos0 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);  // In order to actually reach a position before going to the next position. Otherwise it'll just try to move to all positions at the same time
  faceHigh0(intitialMovementSpeed);
  highPos0 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceLow45(intitialMovementSpeed);
  lowPos45 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceHigh45(intitialMovementSpeed);
  highPos45 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceLow90(intitialMovementSpeed);
  lowPos90 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceHigh90(intitialMovementSpeed);
  highPos90 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceLow135(intitialMovementSpeed);
  lowPos135 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceHigh135(intitialMovementSpeed);
  highPos135 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceLow180(intitialMovementSpeed);
  lowPos180 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceHigh180(intitialMovementSpeed);
  highPos180 = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
  faceTop(intitialMovementSpeed);
  topPos = (MeasureDistance(echoPin, triggerPin));
  delay(delayBetweenSweepMoves);
}

// Sweeps low     // (there are 5 actions here)
void CasualSweepLow1() {
  bool done = false;
  while (!done) {
    faceLow180(25);
    MeasureAndReact(lowPos180);
    if (hasReacted)
      break;
    faceLow135(25);
    MeasureAndReact(lowPos135);
    if (hasReacted)
      break;
    faceLow90(25);
    MeasureAndReact(lowPos90);
    if (hasReacted)
      break;
    faceLow45(25);
    MeasureAndReact(lowPos45);
    if (hasReacted)
      break;
    faceLow0(25);
    MeasureAndReact(lowPos0);
    done = true;
  }
}

void CasualSweepLow2() {
  bool done = false;
  while (!done) {
    faceLow0(25);
    MeasureAndReact(lowPos0);
    if (hasReacted)
      break;
    faceLow45(25);
    MeasureAndReact(lowPos45);
    if (hasReacted)
      break;
    faceLow90(25);
    MeasureAndReact(lowPos90);
    if (hasReacted)
      break;
    faceLow135(25);
    MeasureAndReact(lowPos135);
    if (hasReacted)
      break;
    faceLow180(25);
    MeasureAndReact(lowPos180);
    done = true;
  }
}

void CasualSweepLow3() {
  bool done = false;
  while (!done) {
    faceLow135(25);
    MeasureAndReact(lowPos135);
    if (hasReacted)
      break;
    faceLow45(25);
    MeasureAndReact(lowPos45);
    if (hasReacted)
      break;
    faceLow90(25);
    MeasureAndReact(lowPos90);
    done = true;
  }
}

void CasualSweepLow4() {
  bool done = false;
  while (!done) {
    faceLow180(25);
    MeasureAndReact(lowPos135);
    if (hasReacted)
      break;
    faceLow0(25);
    MeasureAndReact(lowPos45);
    if (hasReacted)
      break;
    done = true;
  }
}

void CasualSweepLow5() {
  faceLow90(25);
  MeasureAndReact(lowPos135);
}

// Sweeps high     // (there are 6 actions here)
void CasualSweepHigh1() {
  bool done = false;
  while (!done) {
    faceHigh180(25);
    MeasureAndReact(highPos180);
    if (hasReacted)
      break;
    faceHigh135(25);
    MeasureAndReact(highPos135);
    if (hasReacted)
      break;
    faceHigh90(25);
    MeasureAndReact(highPos90);
    if (hasReacted)
      break;
    faceHigh45(25);
    MeasureAndReact(highPos45);
    if (hasReacted)
      break;
    faceHigh0(25);
    MeasureAndReact(highPos0);
    done = true;
  }
}

void CasualSweepHigh2() {
  bool done = false;
  while (!done) {
    faceHigh0(25);
    MeasureAndReact(highPos0);
    if (hasReacted)
      break;
    faceHigh45(25);
    MeasureAndReact(highPos45);
    if (hasReacted)
      break;
    faceHigh90(25);
    MeasureAndReact(highPos90);
    if (hasReacted)
      break;
    faceHigh135(25);
    MeasureAndReact(highPos135);
    if (hasReacted)
      break;
    faceHigh180(25);
    MeasureAndReact(highPos180);
    done = true;
  }
}

void CasualSweepHigh3() {
  bool done = false;
  while (!done) {
    faceHigh135(25);
    MeasureAndReact(highPos135);
    if (hasReacted)
      break;
    faceHigh45(25);
    MeasureAndReact(highPos45);
    if (hasReacted)
      break;
    faceHigh90(25);
    MeasureAndReact(highPos90);
    done = true;
  }
}

void CasualSweepHigh4() {
  bool done = false;
  while (!done) {
    faceHigh180(25);
    MeasureAndReact(highPos135);
    if (hasReacted)
      break;
    faceHigh0(25);
    MeasureAndReact(highPos45);
    if (hasReacted)
      break;
    faceTop(25);
    MeasureAndReact(topPos);
    done = true;
  }
}

void CasualSweepHigh5() {
  faceHigh90(25);
  MeasureAndReact(highPos135);
}

void CasualSweepTop() {
  faceTop(25);
  MeasureAndReact(topPos);
}

// Sweeps mixed high and low      // (there are 6 actions here)
void CasualSweepMixed1() {
  bool done = false;
  while (!done) {
    faceHigh180(25);
    MeasureAndReact(highPos180);
    if (hasReacted)
      break;
    faceLow45(25);
    MeasureAndReact(lowPos45);
    if (hasReacted)
      break;
    faceHigh90(25);
    MeasureAndReact(highPos90);
    if (hasReacted)
      break;
    faceLow90(25);
    MeasureAndReact(lowPos90);
    if (hasReacted)
      break;
    faceHigh0(25);
    MeasureAndReact(highPos0);
    done = true;
  }
}

void CasualSweepMixed2() {
  bool done = false;
  while (!done) {
    faceHigh135(25);
    MeasureAndReact(highPos135);
    if (hasReacted)
      break;
    faceLow0(25);
    MeasureAndReact(lowPos0);
    if (hasReacted)
      break;
    faceLow180(25);
    MeasureAndReact(lowPos180);
    if (hasReacted)
      break;
    faceHigh180(25);
    MeasureAndReact(highPos180);
    if (hasReacted)
      break;
    faceHigh90(25);
    MeasureAndReact(highPos90);
    done = true;
  }
}

void CasualSweepMixed3() {
  bool done = false;
  while (!done) {
    faceLow135(25);
    MeasureAndReact(lowPos135);
    if (hasReacted)
      break;
    faceHigh45(25);
    MeasureAndReact(highPos45);
    if (hasReacted)
      break;
    faceHigh135(25);
    MeasureAndReact(highPos135);
    if (hasReacted)
      break;
    faceLow90(25);
    MeasureAndReact(lowPos90);
    done = true;
  }
}

void CasualSweepMixed4() {
  bool done = false;
  while (!done) {
    faceHigh135(25);
    MeasureAndReact(highPos135);
    if (hasReacted)
      break;
    faceLow180(25);
    MeasureAndReact(lowPos180);
    if (hasReacted)
      break;
    faceTop(25);
    MeasureAndReact(topPos);
    done = true;
  }
}

void CasualSweepMixed5() {
  bool done = false;
  while (!done) {
    faceHigh45(25);
    MeasureAndReact(highPos45);
    if (hasReacted)
      break;
    faceLow0(25);
    MeasureAndReact(lowPos0);
    done = true;
  }
}

void CasualSweepMixed6() {
  bool done = false;
  while (!done) {
    faceHigh90(25);
    MeasureAndReact(highPos90);
    if (hasReacted)
      break;
    faceLow180(25);
    MeasureAndReact(lowPos180);
    if (hasReacted)
      break;
    faceLow0(25);
    MeasureAndReact(lowPos0);
    done = true;
  }
}


//--------------------------- Idles ---------------------------//
// (there are 9 actions here)
void Dance1() {
  Serial.println("Dance 1 started.");
  faceLow90(10);
  MoveTo(baseServo, 60, 8);
  MoveTo(neckServo, 60, 8);
  MoveTo(neckServo, 90, 8);
  MoveTo(baseServo, 120, 8);
  MoveTo(neckServo, 60, 8);
  MoveTo(neckServo, 90, 8);
  MoveTo(baseServo, 70, 8);
  MoveTo(neckServo, 35, 8);
  MoveTo(neckServo, 90, 8);
  MoveTo(baseServo, 110, 8);
  MoveTo(neckServo, 35, 8);
  MoveTo(neckServo, 90, 8);
  MoveTo(baseServo, 35, 8);
  MoveTo(neckServo, 55, 8);
  MoveTo(neckServo, 75, 8);
  MoveTo(baseServo, 135, 8);
  MoveTo(neckServo, 75, 8);
  MoveTo(neckServo, 55, 8);
  MoveTo(baseServo, 70, 8);
  MoveTo(neckServo, 35, 8);
  MoveTo(neckServo, 90, 8);
  MoveTo(baseServo, 110, 8);
  MoveTo(neckServo, 35, 8);
  MoveTo(neckServo, 90, 8);
  Serial.println("Dance 1 ended.");
  faceLow90(10);
}

void Dance2() {
  Serial.println("Dance 2 started.");
  faceLow90(10);
  MoveTo(headServo, 45, 1);
  MoveTo(baseServo, 75, 5);
  MoveTo(neckServo, 30, 5);
  MoveTo(neckServo, 75, 5);
  MoveTo(headServo, 135, 1);
  MoveTo(baseServo, 105, 5);
  MoveTo(neckServo, 30, 5);
  MoveTo(neckServo, 75, 5);
  MoveTo(headServo, 90, 5);
  MoveTo(headServo, 35, 1);
  MoveTo(headServo, 145, 1);
  MoveTo(headServo, 0, 1);
  MoveTo(headServo, 180, 1);
  MoveTo(headServo, 75, 1);
  MoveTo(headServo, 105, 1);
  MoveTo(headServo, 90, 5);
  MoveTo(headServo, 105, 1);
  MoveTo(headServo, 75, 1);
  MoveTo(headServo, 180, 1);
  MoveTo(headServo, 0, 1);
  MoveTo(headServo, 145, 1);
  MoveTo(headServo, 35, 1);
  MoveTo(headServo, 90, 5);
  MoveTo(neckServo, 75, 5);
  MoveTo(neckServo, 30, 5);
  MoveTo(baseServo, 105, 5);
  MoveTo(headServo, 135, 1);
  MoveTo(neckServo, 75, 5);
  MoveTo(neckServo, 30, 5);
  MoveTo(baseServo, 75, 5);
  MoveTo(headServo, 45, 1);
  faceLow90(10);
  Serial.println("Dance 2 ended.");
}

void Headbang() {
  Serial.println("Headbang started.");
  faceHigh90(10);
  for (int i = 0; i < 3; i++) {
    MoveTo(neckServo, 85, 2);
    MoveTo(headServo, 165, 2);
    MoveTo(neckServo, 25, 2);
    MoveTo(headServo, 25, 2);
    MoveTo(baseServo, 85, 2);
    MoveTo(neckServo, 85, 2);
    MoveTo(headServo, 165, 2);
    MoveTo(neckServo, 25, 2);
    MoveTo(headServo, 25, 2);
    MoveTo(baseServo, 95, 2);
    MoveTo(neckServo, 85, 2);
    MoveTo(headServo, 165, 2);
    MoveTo(neckServo, 25, 2);
    MoveTo(headServo, 25, 2);
    MoveTo(baseServo, 90, 2);
  }
  Serial.println("Headbang ended.");
  faceLow90(8);
}

void SwayHead1() {
  faceLow45(5);
  MoveTo(headServo, 80, 5);
  MoveTo(baseServo, 135, 20);
  MoveTo(headServo, 110, 5);
  MoveTo(baseServo, 45, 20);
  faceLow90(10);
}

void SwayHead2() {
  faceLow180(5);
  MoveTo(headServo, 125, 5);
  MoveTo(baseServo, 0, 20);
  MoveTo(headServo, 65, 5);
  MoveTo(baseServo, 180, 20);
  faceLow90(10);
}

void SwayHead3() {
  faceHigh45(5);
  MoveTo(headServo, 80, 5);
  MoveTo(baseServo, 135, 20);
  MoveTo(headServo, 110, 5);
  MoveTo(baseServo, 45, 20);
  faceLow90(10);
}

void SwayHead4() {
  faceHigh180(5);
  MoveTo(headServo, 125, 5);
  MoveTo(baseServo, 0, 20);
  MoveTo(headServo, 65, 5);
  MoveTo(baseServo, 180, 20);
  faceLow90(10);
}

void SwayHead5() {
  faceHigh90(5);
  MoveTo(headServo, 170, 10);
  MoveTo(neckServo, 90, 20);
  MoveTo(headServo, 10, 10);
  MoveTo(neckServo, 10, 20);
  MoveTo(neckServo, 90, 20);
  faceLow90(10);
}

void SitUpIdle() {
  faceTop(20);
  MoveTo(headServo, 25, 10);
  MoveTo(headServo, 90, 10);
  delay(1000);
  MoveTo(headServo, 155, 10);
  MoveTo(neckServo, 25, 10);
  delay(1000);
  faceLow90(20);
}

//--------------------------- Facing Directions ---------------------------//
// Facing directions
void faceLow0(int speed) {
  MoveTo(headServo, 90, speed);  // Head servo 90° is face straight.
  MoveTo(baseServo, 0, speed);   // Base at 90° is face forward, 180° is face left, 0° is face right
  MoveTo(neckServo, 90, speed);  // 90° is look straight forward. You can't really go above this safely since it then translates in facing downwards. 0° is look straight up.
  Serial.println("FaceLow0");
}

void faceLow45(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 45, speed);
  MoveTo(neckServo, 90, speed);
  Serial.println("FaceLow45");
}
void faceLow90(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 90, speed);
  MoveTo(neckServo, 90, speed);
}
void faceLow135(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 135, speed);
  MoveTo(neckServo, 90, speed);
}
void faceLow180(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 180, speed);
  MoveTo(neckServo, 90, speed);
}
void faceHigh0(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 0, speed);
  MoveTo(neckServo, 45, speed);
}

void faceHigh45(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 45, speed);
  MoveTo(neckServo, 45, speed);
}
void faceHigh90(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 90, speed);
  MoveTo(neckServo, 45, speed);
}
void faceHigh135(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 135, speed);
  MoveTo(neckServo, 45, speed);
}
void faceHigh180(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 180, speed);
  MoveTo(neckServo, 45, speed);
}
void faceTop(int speed) {
  MoveTo(headServo, 90, speed);
  MoveTo(baseServo, 90, speed);
  MoveTo(neckServo, 0, speed);
}




/////////////////////////////////////////////////////////////////////////
//--------------------------- Using melodies---------------------------//
////////////////////////////////////////////////////////////////////////
//For singing melodies and speaking 'words'

// This piece of code comes from the Arduino site and is only edited by me to be used for my project.
void PlayYankeeDoodle() {

  // Adding some movement in a random direction. This way buddy sings to different locations instead of only facing forward.
  MoveTo(baseServo, random(0, 180), random(2, 25));
  MoveTo(neckServo, random(10, 80), random(2, 25));   // Raising your head whilst saying seems appropriate.
  MoveTo(headServo, random(10, 170), random(2, 25));  // Buddy has a random angle of his head when singing.
  delay(500);                                         // We wait half a second to be sure that the Servo's are done moving before singing.

  // notes in the melody:
  int melody[] = {

    NOTE_C5, NOTE_C5, NOTE_D5, NOTE_E5,
    NOTE_C5, NOTE_E5, NOTE_D5,
    NOTE_C5, NOTE_C5, NOTE_D5, NOTE_E5,
    NOTE_C5, NOTE_B5,
    NOTE_C5, NOTE_C5, NOTE_D5, NOTE_E5,
    NOTE_F5, NOTE_E5, NOTE_D5, NOTE_C5,
    NOTE_B5, NOTE_G4, NOTE_A5, NOTE_B5,
    NOTE_C5, NOTE_C5

  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    4, 4, 4, 4,
    4, 4, 2,
    4, 4, 4, 4,
    2, 2,
    4, 4, 4, 4,
    4, 4, 4, 4,
    4, 4, 4, 4,
    4, 4, 4, 4,
    2, 2
  };

  // iterate over the notes of the melody:

  for (int thisNote = 0; thisNote < 27; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
  faceLow90(25);  // Reset face orientation after singing.
}

void PlayAuClaireDeLaLune() {
  // Adding some movement in a random direction. This way buddy sings to different locations instead of only facing forward.
  MoveTo(baseServo, random(0, 180), random(2, 25));
  MoveTo(neckServo, random(10, 80), random(2, 25));   // Raising your head whilst saying seems appropriate.
  MoveTo(headServo, random(10, 170), random(2, 25));  // Buddy has a random angle of his head when singing.
  delay(500);                                         // We wait half a second to be sure that the Servo's are done moving before singing.

  // notes in the melody:
  int melody[] = {
    NOTE_C5, NOTE_C5, NOTE_C5, NOTE_D5,
    NOTE_E5, NOTE_D5,
    NOTE_C5, NOTE_E5, NOTE_D5, NOTE_D5,
    NOTE_C5,
    NOTE_C5, NOTE_C5, NOTE_C5, NOTE_D5,
    NOTE_E5, NOTE_D5,
    NOTE_C5, NOTE_E5, NOTE_D5, NOTE_D5,
    NOTE_C5,
    NOTE_C5, NOTE_C5, NOTE_C5, NOTE_C5,
    NOTE_A5, NOTE_A5,
    NOTE_D5, NOTE_C5, NOTE_B5, NOTE_A5,
    NOTE_G4,
    NOTE_C5, NOTE_C5, NOTE_C5, NOTE_D5,
    NOTE_E5, NOTE_D5,
    NOTE_C5, NOTE_E5, NOTE_D5, NOTE_D5,
    NOTE_C5
  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    4, 4, 4, 4,
    2, 2,
    4, 4, 4, 4,
    1,
    4, 4, 4, 4,
    2, 2,
    4, 4, 4, 4,
    1,
    4, 4, 4, 4,
    2, 2,
    4, 4, 4, 4,
    1,
    4, 4, 4, 4,
    2, 2,
    4, 4, 4, 4,
    1,
    4, 4, 4, 4,
    2, 2,
    4, 4, 4, 4,
    1
  };

  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 44; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
  faceLow90(25);  // Reset face orientation after singing.
}

void Speak1() {
  // notes in the melody:
  // Adding some movement in a random direction. This way buddy sings to different locations instead of only facing forward.
  MoveTo(baseServo, random(0, 180), random(2, 25));
  MoveTo(neckServo, random(0, 90), random(2, 25));    // Just a random angle for the neck.
  MoveTo(headServo, random(10, 170), random(2, 25));  // Buddy has a random angle of his head when speaking.
  delay(500);                                         // We wait half a second to be sure that the Servo's are done moving before speaking.


  int melody[] = {

    NOTE_C5, NOTE_C5, NOTE_G4, NOTE_B5

  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    8, 4, 8, 3
  };

  // iterate over the notes of the melody:

  for (int thisNote = 0; thisNote < 4; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
}

void Speak2() {
  // Adding some movement in a random direction. This way buddy sings to different locations instead of only facing forward.
  MoveTo(baseServo, random(0, 180), random(2, 25));
  MoveTo(neckServo, random(0, 90), random(2, 25));    // Just a random angle for the neck.
  MoveTo(headServo, random(10, 170), random(2, 25));  // Buddy has a random angle of his head when speaking.
  delay(500);                                         // We wait half a second to be sure that the Servo's are done moving before speaking.
  // notes in the melody:
  int melody[] = {

    NOTE_B0, NOTE_D2, NOTE_E4, NOTE_B5

  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    4, 8, 8, 4
  };

  // iterate over the notes of the melody:

  for (int thisNote = 0; thisNote < 4; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
}

void Speak3() {
  // Adding some movement in a random direction. This way buddy sings to different locations instead of only facing forward.
  MoveTo(baseServo, random(0, 180), random(2, 25));
  MoveTo(neckServo, random(0, 90), random(2, 25));    // Just a random angle for the neck.
  MoveTo(headServo, random(10, 170), random(2, 25));  // Buddy has a random angle of his head when speaking.
  delay(500);                                         // We wait half a second to be sure that the Servo's are done moving before speaking.
                                                      // notes in the melody:
  int melody[] = {

    NOTE_B0, NOTE_D2, NOTE_E4, NOTE_B5, NOTE_D3, NOTE_D3, NOTE_B6

  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    4, 8, 8, 4, 8, 8, 4
  };

  // iterate over the notes of the melody:

  for (int thisNote = 0; thisNote < 7; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
}

void Speak4() {
  // Adding some movement in a random direction. This way buddy sings to different locations instead of only facing forward.
  MoveTo(baseServo, random(0, 180), random(2, 25));
  MoveTo(neckServo, random(0, 90), random(2, 25));    // Just a random angle for the neck.
  MoveTo(headServo, random(10, 170), random(2, 25));  // Buddy has a random angle of his head when speaking.
  delay(500);                                         // We wait half a second to be sure that the Servo's are done moving before speaking.
                                                      // notes in the melody:
  int melody[] = {

    NOTE_B0, NOTE_D2, NOTE_B0, NOTE_D1, NOTE_D3, NOTE_D2, NOTE_B0

  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    4, 8, 4, 8, 8, 2, 4
  };

  // iterate over the notes of the melody:

  for (int thisNote = 0; thisNote < 7; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
}

void SpeakCurious() {
  // notes in the melody:
  int melody[] = {

    NOTE_B0, NOTE_B2, NOTE_E2, NOTE_E2, NOTE_B4

  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    8, 2, 8, 8, 2
  };

  // iterate over the notes of the melody:

  for (int thisNote = 0; thisNote < 5; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
}

void SpeakStartled1() {
  // notes in the melody:
  int melody[] = {

    NOTE_B4, NOTE_B4, NOTE_B4

  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    8, 8, 8
  };

  // iterate over the notes of the melody:

  for (int thisNote = 0; thisNote < 8; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
}

void SpeakStartled2() {
  // notes in the melody:
  int melody[] = {

    NOTE_B0, NOTE_B0, NOTE_B0

  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    8, 8, 8
  };

  // iterate over the notes of the melody:

  for (int thisNote = 0; thisNote < 8; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
}

void PlayTwinkleTwinkleLittleStar() {
  // Adding some movement in a random direction. This way buddy sings to different locations instead of only facing forward.
  MoveTo(baseServo, random(0, 180), random(2, 25));
  MoveTo(neckServo, random(10, 80), random(2, 25));   // Raising your head whilst saying seems appropriate.
  MoveTo(headServo, random(10, 170), random(2, 25));  // Buddy has a random angle of his head when singing.
  delay(500);                                         // We wait half a second to be sure that the Servo's are done moving before singing.

  // notes in the melody:
  int melody[] = {
    NOTE_C5, NOTE_C5, NOTE_G6, NOTE_G6,
    NOTE_A6, NOTE_A6, NOTE_G5,
    NOTE_F5, NOTE_F5, NOTE_E5, NOTE_E5,
    NOTE_D5, NOTE_D5, NOTE_C5,
    NOTE_G5, NOTE_G5, NOTE_F5, NOTE_F5,
    NOTE_E5, NOTE_E5, NOTE_D5,
    NOTE_G5, NOTE_G5, NOTE_F5, NOTE_F5,
    NOTE_E5, NOTE_E5, NOTE_D5,
    NOTE_C5, NOTE_C5, NOTE_G5, NOTE_G5,
    NOTE_A6, NOTE_A5, NOTE_G5,
    NOTE_F5, NOTE_F5, NOTE_E5, NOTE_E5,
    NOTE_D5, NOTE_D5, NOTE_C5
  };

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  float noteDurations[] = {

    4, 4, 4, 4,
    4, 4, 2,
    4, 4, 4, 4,
    4, 4, 2,
    4, 4, 4, 4,
    4, 4, 2,
    4, 4, 4, 4,
    4, 4, 2,
    4, 4, 4, 4,
    4, 4, 2,
    4, 4, 4, 4,
    4, 4, 2
  };

  // iterate over the notes of the melody:
  for (int thisNote = 0; thisNote < 42; thisNote++) {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];

    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.

    // the note's duration + 30% seems to work well:

    int pauseBetweenNotes = noteDuration * 1.30;

    delay(pauseBetweenNotes);

    // stop the tone playing:

    noTone(buzzerPin);
  }
  faceLow90(25);  // Reset face orientation after singing.
}

look like memory issue.
Too much data and code for old good Nano.

The code is written with absolutely no regard for the fact that the Nano has only 2k of memory
A bunch of long text messages are not loaded into flash. The data format is chosen without regard to the content:

This array could easily be described as a byte instead of a float - and it will take up four times less space. And there are half a dozen such arrays in the code

1 Like

Dear b707,

Thank you very much for your fast reply!
And you are totally right about the code being written with no regard of the 2k memory.
I have honestly never even considered that part and only read the output as if saying "there is still room left".
But this also explains why it worked before and stopped working later on.

I am going to try to cut down on the memory used and try again.
And try to learn a thing or two about memory allocation, instead of treating the arduino like it has inifinite memory.

Thanks again!

You are welcome :slight_smile:
As a first step start from using F() macro for all constant string printing statements.

Change

to
Serial.println(F("CasualSweepLow1"));

throughout the code

I'm definately going to change that as well!

But changing the float to byte seemed to have done the trick to at least run the code again on the Nano! :smiley:

So it was most definately a memory problem.
A very good lesson for a me as a newbie, thank you! :slight_smile:

Time to read up on state machines and the use of millis() for timing :wink: the second one is relatively easy, the first one requires you to think how to split your functionality. And forget that for-loops (and while-loops) exist for the purpose that you're using them for.

Take one of your functions, e.g. SpeakStartled1. The first thing to do is get rid of the for-loop. You declare a static variable thisNote that replaces the variable in the for-loop. Because the variable is static, it will be remembered between successive callsof the function; because it's local to the function, it is only known inside the function.

void smSpeakStartled1()
{
  // notes in the melody:
  int melody[] = {
      NOTE_B4, NOTE_B4, NOTE_B4};

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  byte noteDurations[] = {
    8, 8, 8};

  static int thisNote=0;

Now instead of the for-loop, we use an if statement

  //for (int thisNote = 0; thisNote < 8; thisNote++)
  // if not all notes of the melody have been played
  if (thisNote < 8)
  {

NOTE: you only have three notes in this melody; why do you have a for-loop that counts eight?

and at the end of the if statement we increment thisNote.

    // next note of the melody
    thisNote++;

If the full melody was played, we reset thisNote so the next time that you want to play the melody it starts from the beginning. The full function now looks like

/*
  SpeakStartled1 modifiied to use statemachine and millis() based timing
*/
void smSpeakStartled1()
{
  // notes in the melody:
  int melody[] = {
    NOTE_B4, NOTE_B4, NOTE_B4};

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  byte noteDurations[] = {
    8, 8, 8};

  static int thisNote = 0;

  // iterate over the notes of the melody:

  //for (int thisNote = 0; thisNote < 8; thisNote++)
  if (thisNote < 8)
  {

    // to calculate the note duration, take one second divided by the note type.

    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.

    int noteDuration = 1000 / noteDurations[thisNote];
    tone(buzzerPin, melody[thisNote], noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);

    // stop the tone playing:
    noTone(buzzerPin);

    // next note of the melody
    thisNote++;
  }
  else
  {
    // when all notes of the melody have been played, reset for the next time that we want to play the melody again
    thisNote = 0;
  }
}

You will have to call this function repeatedly from loop().

void loop()
{
  smSpeakStartled1();
}

This will play that melody forever; you more than likely don't want that so you need an indication that the melody is finished. For that, we will let the function return a value that indicates if all notes have been played or not.

/*
  SpeakStartled1 modifiied to use statemachine and millis() based timing
  Returns:
    true if melody was completed, else false
*/
bool smSpeakStartled1()
{
  // flag indicating if melody was completed (true) or not (false)
  bool rb = false;
  ...
  ...

If the playing of the melody is complete, we will set rb to true. At the end of the function, we will return rb

bool smSpeakStartled1()
{
  // flag indicating if melody was completed (true) or not (false)
  bool rb = false;
  ...
  ...

  //for (int thisNote = 0; thisNote < 8; thisNote++)
  if (thisNote < 8)
  {
    ...
    ...
  }
    else
  {
    // when all notes of the melody have been played, reset for the next time that we want to play the melody again
    thisNote = 0;
    rb=true;
  }
  // tell the calling function the state of the playing of the melody
  return rb;
}

And in loop() we can now test

void loop()
{
  if(smSpeakStartled1() == true)
  {
    Serial.println(F("smSpeakStartled1() complete");
    delay (5000);
  }
}

This will play the melody, wait for 5 seconds and plays it again.

Time to think about a finite state machine. You have some states

  1. tone(buzzerPin, melody[thisNote], noteDuration) is actually two states; the first one is the "starting of the playing of the tone and the second one is the duration. You could basically split that into tone(buzzerPin, melody[thisNote]) and delay(noteDuration).
  2. delay(pauseBetweenNotes)

So we can have three states placed in an enumerated type and we use a static variable to remember what we are doing

  enum class STATE : uint8_t
  {
    STARTNOTE,
    PLAYNOTE,
    WAIT,
  };


  // the state of the state machine
  static STATE state;

The basic implementation

  switch (state)
  {
    case STATE::STARTNOTE:
      break;
    case STATE::PLAYNOTE:
      break;
    case STATE::WAIT:
      break;
  }

And next you can implement the different states; the full function

/*
  SpeakStartled1 modifiied to use statemachine and millis() based timing
*/
/*
  SpeakStartled1 modifiied to use statemachine and millis() based timing
  Returns:
    true if melody was completed, else false
*/
bool smSpeakStartled1()
{
  // flag indicating if melody was completed (true) or not (false)
  bool rb = false;

  // notes in the melody:
  int melody[] = {
    NOTE_B4, NOTE_B4, NOTE_B4};

  // note durations: 4 = quarter note, 8 = eighth note, etc.:
  byte noteDurations[] = {
    8, 8, 8};

  enum class STATE : uint8_t
  {
    STARTNOTE,
    PLAYNOTE,
    WAIT,
  };

  // the state of the state machine
  static STATE state;

  // the start time that we started playing a note or started the delay
  static uint32_t startTime;

  // note that we're playing
  static uint16_t thisNote = 0;

  // the duration for the note that is playing
  uint16_t noteDuration;
  // delay between notes
  uint16_t pauseBetweenNotes;

  switch (state)
  {
    case STATE::STARTNOTE:
      // start the note
      tone(buzzerPin, melody[thisNote]);
      //calculate the duration
      noteDuration = 1000 / noteDurations[thisNote];
      // remember the startTime
      startTime = millis();
      // go to next state
      state = STATE::PLAYNOTE;
      // for debugging
      Serial.println(F("Switching to PLAYNOTE"));
      break;
    case STATE::PLAYNOTE:
      // if the note has played for the given duration
      if (millis() - startTime >= noteDuration)
      {
        // stop the tone playing:
        noTone(buzzerPin);
        // to distinguish the notes, set a minimum time between them.
        // the note's duration + 30% seems to work well:
        pauseBetweenNotes = noteDuration * 1.30;
        // remember the startTime for the delay between notes
        startTime = millis();
        // go to the next state
        state = STATE::WAIT;
        // for debugging
        Serial.println(F("Switching to WAIT"));
      }
      break;
    case STATE::WAIT:
      // if we've waited long enough so we can play the next note
      if (millis() - startTime >= pauseBetweenNotes)
      {
        // next note of the melody
        thisNote++;
        // if we've reached the end of the melody
        if (thisNote >= sizeof(melody) / sizeof(melody[0]))
        {
          thisNote = 0;
          rb = true;
        }
        // next run, start fromthe beginning
        state = STATE::STARTNOTE;
        // for debugging
        Serial.println(F("Switching to STARTNOTE"));
      }
      break;
  }

  // tell the calling function the state of the playing of the melody
  return rb;
}

The code starts in one state, moves to the next state if the tate is complete and so on. At the end, the code goers back to the first state.

I did not look at your other code; implementation of this might or might not be required depending on your needs but it can be the beginning. It compiles but is not tested.

Notes

  1. sizeof(melody) / sizeof(melody[0]))
    This calculates the number of elements of an array; it's independent of the type of array (int, byte, struct etc).
  2. In file → preferences in the IDE, set your warning level to ALL and fix the warnings that you get.
  3. In the function that I modified and in others, you have two arrays, one for the notes of the melody and one for the note durations. You can combine related information in a struct and use an array of structs. A struct is like an entry in a phonebook where a name and a phone number (and possibly other information) is kept together.

I think that that is it. You're welcome to ask questions; I hope that I made the approach clear.

1 Like

Wow, that is an indepth advise! :grinning:
This will definately take some time to go through and to try and maybe implement.
But I will definately try and read up on the mentioned subjects like milis() and the finite state machine.

The later I've heard off but never actually tried to create myself. Though this might be a very useful structure for any other project I might attempt :slightly_smiling_face:

The note you mentioned:
NOTE: you only have three notes in this melody; why do you have a for-loop that counts eight?

Was probably a typo or I might have wanted to add more, but thanks for pointing that out! I can easily fix that.

Thanks again @sterretje, for the elaborate advise and review of my code.

If you set the warning level to all in file → preferences, you will get a warning that those mistakes will / might invoke undefined behaviour. The construction with sizeof that I used prevents that; it simply scales.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.