Sophisticated UselessBox code support needed

Good day!

I'm currently tinkering with the Arduino code for my Useless Box, which operates with 7 servo motors. I have tested all the mechanical movements with simple code segments, ensuring the mechanical and electrical aspects of the project are in order. However, integrating all the code has proven to be a bit too sophisticated for my skills. Despite spending weeks trying to resolve the issue myself, and even hiring a coder from Fiverr, the project still does not work as intended.

I am hopeful that there is a coding wizard here who could assist me in properly operating the 7 servo motors. Easy peasy. I would very appreciate some help with this.

So the pictures of the Project in progress:
All the 3D parts:

The whole contraption without box. It is quite tiny.

A pitcture of the switch rotating mechanism

Here I will paste the "most advanced" code so for and sum up the problems which I have currently:

/*
 * Changelog:
 * V0 - First Draft Code by Saeed
 * V1 - Changes done by Nik:
      - Changed some Servo Position names and Start and end Positions
      - Excluded the LED Eyes function for now. I will just turn the LED on when DingDing gets out of the box to S7_OutPos
      - "Deleted" the Cases. I will set them once I have some time. So lets work for now only with case 1. I made the example what should happen in Cas1
  *V1.1 
      - I did it like this and this worked well with the switch (On/off Switch) and the code like:
      ...
      Switch Pin 13;
      ...
      
      void loop() {
       switchState = digitalRead(switchPin);
      if (switchState != lastSwitchState) {
       if (switchState == HIGH) {
      int mode = random(2); 
      ...
      And then going into different cases

  
      Request for V2
      Could 
  * V2 by Saeed
    - Make a function "void MoveServoHuman (Servo, Position)" which then can be used to move a defined Servo to a certain Position)
    - Somehow in ThinkerCad the "human Movement" of the Servos is not as intendet from me. 
    The Servo should start moving normal fast and getting slower at the very last bit of movement until reaching the final position. 
    

*/


#include <Servo.h>
                      //Switch will workwith 1 GND pin and 1 Digital Pin , no need of VCC pin :)
#define SwitchPin 3   // Digital Pin for Switch set on PCB
#define ledPin 3      // DingDingLED Eyes

unsigned long previousMillis = 0;  
int ledState = LOW;
int busy_flag=LOW;


//Servo Pins:
#define S1_PIN 12 // on PCB slot1
#define S2_PIN 5 
#define S3_PIN 6 
#define S4_PIN 7 
#define S5_PIN 8 
#define S6_PIN 9 
#define S7_PIN 10 

//Servo Objects:
Servo S1_SP; //Switch Pusher
Servo S2_LP; //Lid Pusher
Servo S3_FP; //Flag Pusher
Servo S4_ST; //Switch Turner (360° Servo)
Servo S5_SL; //Switch Level
Servo S6_IO; //Iris Opener
Servo S7_DP; //DingDing Pusher

//Start & End Servo Positions:

//Switch Pusher
 int S1_StartPos = 130; //Arm In the box
 int S1_MidPos = 100;   //Arm lurking 
 int S1_EndPos = 52;    //Arm pushed switch
 
// Lid Pusher
 int S2_ClosePos = 30; // Lid Closed
 int S2_OpenPos = 60;  // Lid Open

 //Flag Pusher
 int S3_StartPos = 30; // Pos in the Box
 int S3_FlagPos_L = 60; 
 int S3_FlagPos_R = 90;

// Switch Turner
 int S4_Turn_R = 30;  // Turn CW
 int S4_Hold = 0;     // No turn
 int S4_Turn_L = -30; // Turn CCW

 //Switch Level
 int S5_UpPos = 30;   //Switch Up
 int S5_DownPos = 60; // Switch down

 // Iris Opener
 int S6_OpenPos = 30; // Iris open
 int S6_ClosePos = 60; // Iris closed

 // DingDing Pusher
 int S7_InPos = 30; // DingDing In Box
 int S7_OutPos = 60; //DingDing out of box


unsigned long startTime;
float movementProgress;


//---------------VOID SETUP---------------
void setup() {

  S1_SP.attach(S1_PIN);
  S2_LP.attach(S2_PIN); 
  S3_FP.attach(S3_PIN); 
  S4_ST.attach(S4_PIN); 
  S5_SL.attach(S5_PIN); 
  S6_IO.attach(S6_PIN); 
  S7_DP.attach(S7_PIN); 

// Set all Servos on starting Position
  S1_SP.write(S1_StartPos);
  S3_FP.write(S3_StartPos);
  S2_LP.write(S2_ClosePos);
  S6_IO.write(S6_OpenPos); //Open Iris before Switch is up
  S4_ST.write(S4_Hold);
  S5_SL.write(S5_UpPos);
  S7_DP.write(S7_InPos);

  // Setup Debug Serial
  Serial.begin(9600);
  pinMode(SwitchPin, INPUT_PULLUP); // Set the SwitchPin as input with internal pull-up resistor
  attachInterrupt(digitalPinToInterrupt(SwitchPin),Rand_Case_Switch, FALLING); // Attach the interrupt
  startTime = millis();
  
}


//---------------VOID LOOP---------------
void loop() {
  //DingDing_leds(500);
  //Jitter();
  Rand_Case_Switch();
}

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

// FUNCTION 1): For Check Servo Movment Debug
void servo_check(Servo &theServo, int angle)
{
theServo.write(angle);
}


// FUNCTION 2): For Rumbles the Lid in Idle
void Jitter() //
{

 if (busy_flag == LOW) {
    int pos = random(0, 180); // Random servo position
    S2_LP.write(pos);
    
    // Introduce jitter occasionally
    if (random(0, 100) < 10) { // Adjust probability as needed
      int originalPos = pos;
      int jitterRange = 10; // Jitter range in degrees
      int jitterTime = 500; // Jitter time in milliseconds
      
      // Create a rumbling effect
      for (int i = 0; i < 5; i++) { // Number of rumble cycles
        int jitter = random(-jitterRange, jitterRange);
        S2_LP.write(originalPos + jitter);
        delay(jitterTime);
        S2_LP.write(originalPos - jitter);
        delay(jitterTime);
      }
      
      S2_LP.write(originalPos); // Return to the original position
    }
  }

}

/*
void DingDing_leds(int interval)
{
   unsigned long currentMillis1 = millis();

  if (currentMillis1 - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis1;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
  
}
*/

// Choooses Case if switch is pushed
void Rand_Case_Switch()
{
    busy_flag=HIGH;
    int caseNumber = generateRandomCase();
    switch (caseNumber) {
    case 1:
      // Code for Case 1
      Serial.println("Case 1");
      case1();
      break;
      
    case 2:
      // Code for Case 2
      Serial.println("Case 2");
      case2();
      break;
      
    case 3:
      // Code for Case 3
      Serial.println("Case 3");
      case3();
      break;
      
    case 4:
      // Code for Case 4
      Serial.println("Case 4");
      case4();
      break;
      
    case 5:
      // Code for Case 5
      Serial.println("Case 5");
      case5();
      break;
      
    case 6:
      // Code for Case 6
      Serial.println("Case 6");
      case6();
      break;
      
    case 7:
      // Code for Case 7
      Serial.println("Case 7");
      case7();
      break;
      
    default:
      // Default case (shouldn't be reached)
      Serial.println("Unknown case");
      break;
  }


}

// Function to set Probability of the Cases
int generateRandomCase() {
  float probabilities[] = {0.8, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01}; // Adjust probabilities as needed
  int cases[] = {1, 2, 3, 4, 5, 6, 7};
  float randValue = random(100) / 100.0;
  
  float cumulativeProb = 0.0;
  for (int i = 0; i < sizeof(probabilities) / sizeof(float); i++) {
    cumulativeProb += probabilities[i];
    if (randValue < cumulativeProb) {
      return cases[i];
    }
  }
  
  // Fallback case (shouldn't be reached)
  return cases[sizeof(cases) / sizeof(int) - 1];
}


// Servo Movement with an slowed down Endspeed
void MoveServoHuman(Servo &theServo, int Position) {
  int initialPosition = theServo.read();
  int targetPosition = constrain(Position, 0, 180);  // Make sure the target position is within valid range
  int currentPosition = initialPosition;

  //Serial.write(theServo);
  //Serial.write(Position);

  
  
  int speed = 5;  // Initial speed of movement
  int minSpeed = 1;  // Minimum speed to ensure smooth final positioning
  
  while (currentPosition != targetPosition) {
    if (currentPosition < targetPosition) {
      currentPosition += speed;
      if (currentPosition > targetPosition) {
        currentPosition = targetPosition;
      }
    } else {
      currentPosition -= speed;
      if (currentPosition < targetPosition) {
        currentPosition = targetPosition;
      }
    }
    
    theServo.write(currentPosition);
    
    // Gradually decrease speed as servo approaches final position
    if (abs(targetPosition - currentPosition) < 10) {
      speed = max(minSpeed, speed - 10); //-1 Start
    }
    
    delay(20);  // Delay for smoother movement
  }
}

//---------------CASES---------------

// CASE 1: Simple Pusher
void case1(){ 
   MoveServoHuman (S1_SP, S1_EndPos); //-> The Arm pushes the Switch
   delay(500);  //--> Waits a few ms
   MoveServoHuman (S1_SP, S1_StartPos); //--> Moves Arm back in
  }



 // Case is Same as Case 1  but the arm goes out and stays longer aka. firmer on the switch
void case2(){
   S2_LP.write(S2_OpenPos);                 // Lid of the box opens (normal movement)
   delay(100);                              // wait for some ms
   MoveServoHuman (S7_DP, S7_OutPos);  // Ding Ding comes out of box
   delay(200);                             // wait for some ms
   MoveServoHuman (S1_SP, S1_EndPos); //-> The Arm pushes the Switch
   delay(2000);  //--> Waits a bit more than case 2
   MoveServoHuman (S1_SP, S1_StartPos); //--> Moves Arm back in
   MoveServoHuman (S7_DP, S7_InPos);  // Ding Ding goes back in box
   delay(200);                             // wait for some ms
   S2_LP.write(S2_ClosePos);                 // Lid of the box closes (normal movement)

 
  }


//In this case the switch gets removed from the box and the iris closed
void case3(){ 
   S5_SL.write(S5_DownPos); //Switch gets moved "down" or in the box with no special movement
   delay(500);
   MoveServoHuman (S6_IO, S6_ClosePos); // Iris gets closed smothley
   delay(4000); // waits forever
   
   // --> Then Case 4 inside the box (Turns switch) 
   MoveServoHuman (S6_IO, S6_OpenPos); // Iris gets opened again smothley
   delay(500);
   S5_SL.write(S5_UpPos); //Switch gets moved "up" agai
  }

void case4(){
    S4_ST.write(S4_Turn_R); //The switch gets turned clockwise
    delay(1000); //Move Servo approx 1 sec until the Switch reached 180°  
    S4_ST.write(S4_Hold); //Stop Servo
    busy_flag=LOW; //set back switch state ?! Or is it working like this?
  }

  /* My two problems here to code:
    1) The Switch should always be mechanically turned alternating clockwise 180° and when this case occurs again counter clockwise (180°). So that the switch cabling doesn't get tangled up.
    How does such a case look like?
    Saeed's Response: Bro that's mechanical problem you can use brushes just like in DC motor to avoid the wires being rotated . It will not leave any effect at arduino it'll alsway consier as a switch as it is.

    2) Normally (in other cases) the switch gets pushed by the User and bushed back by the machine. 
    In this "turning case" the switch gets pushed by the User but the machine only turns the switch phisicaly by 180° to solve the case.
    So does the system know again that busy_flag state has changed?
    Saeed's Response: Busy flag is just there for jitter function , you told that there must be an occasional jitter when device is not doing anything else. So 
    this flag tell about if device is busy in another function or not.
   */

  
//In this case the box gives up... or supposes like
void case5(){
  S2_LP.write(S2_OpenPos);                 // Lid of the box opens (normal movement)
  delay(100);                              // wait for some ms
  MoveServoHuman (S7_DP, S7_OutPos);  // Ding Ding comes out of box
  delay(200);                             // wait for some ms¨
  MoveServoHuman (S3_FP, S3_FlagPos_R);  // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_L); // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_R);  // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_L); // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_R);  // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_L); // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_R);  // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_L); // Flag waving from right to left...

   //--> There is a smarter way to do this waving flag?

  // now suddenly the arm switches the switch and everything closes
  MoveServoHuman (S3_FP, S3_StartPos); // -> Flag goes back in
  MoveServoHuman (S1_SP, S1_EndPos); // -> The Arm pushes the Switch
  delay(500);  //--> Waits a few ms
  MoveServoHuman (S1_SP, S1_StartPos); // --> Moves Arm back in
  MoveServoHuman (S7_DP, S7_InPos);   // Ding Ding goes back in box
  delay(200);                             // wait for some ms
  S2_LP.write(S2_ClosePos);                 // Lid of the box closes (normal movement)
  }

void case6(){
  //TBD by me
  }

void case7(){
  unsigned long currentTime = millis();
  
  }



// Restore Servo Positions
void restoreservos() // This func. is used to restore servo positions to their start when intended
{
  S1_SP.write(S1_StartPos);
  S3_FP.write(S3_StartPos);
  S2_LP.write(S2_ClosePos);
  S6_IO.write(S6_OpenPos); //Open Iris before Switch is up
  S4_ST.write(S4_Hold);
  S5_SL.write(S5_UpPos);
  S7_DP.write(S7_InPos);


}

So main problem right now:
The switch can physically be turned by the machine by 180° CW and CCW. Solving the problem of a flicked switch alternatively then pushing it back with the classic uslessbox arm.
So this code still doesn't solve the problem that the switch could be in each state (0 or 1) when I turn the machine on. So the code should always start with the momentarly state of the switch as default and react with a "Case" when the switch is trigered by the user.
Furthermore: In case 4 the switch gets physically turned on the box and so the whole reaction concept has to work when it's turned again.
Do you guys understand the problem?

2nd problem:
The function MoveServoHuman() should move the servos like James Bruton has showed in his video about how to move Servos more "humanly". Which means: the servos de-accelarate steadily but heavily before reachaing it's end position. This function the Fiverr Coder wrote seems not to work as intended even though I worked with the variables.

This is it for now :wink: Thank you guys in advance

No, but do you understand that your switch has THREE different states? The ON state, the OFF state and the state where it is changing from on to off and from off to on? Switches also BOUNCE the contacts when changing from one state to another.

Hello ntcbrnfk

I´m not a wizzard, but I did a little code review. This program seems to have grown orgnically and contains appropriate logic and timing "nodes".

My recommendation is:

Start by designing and coding an object for each servo. This object definition contains all the necessary data such as pin address, min/max value, movement speed and the methods to control the servo.
Finally, there will be a schedule of which servo movements should be executed under which conditions.

Have a nice day and enjoy coding in C++.

i have not understand why big switch must rotate and why it has 6 fixed positions
and

int currentPosition = theServo.read();

does it work? how can lib read out a resistance of servos intern potentiometer? or it shows last written value ?

/*
   Changelog:
   V0 - First Draft Code by Saeed
   V1 - Changes done by Nik:
      - Changed some Servo Position names and Start and end Positions
      - Excluded the LED Eyes function for now. I will just turn the LED on when DingDing gets out of the box to S7_OutPos
      - "Deleted" the Cases. I will set them once I have some time. So lets work for now only with case 1. I made the example what should happen in Cas1
   V1.1
      - I did it like this and this worked well with the switch (On/off Switch) and the code like:
      ...
      Switch Pin 13;
      ...

      void loop() {
       switchState = digitalRead(switchPin);
      if (switchState != lastSwitchState) {
       if (switchState == HIGH) {
      int mode = random(2);
      ...
      And then going into different cases


      Request for V2
      Could
    V2 by Saeed
    - Make a function "void MoveServoHuman (Servo, Position)" which then can be used to move a defined Servo to a certain Position)
    - Somehow in ThinkerCad the "human Movement" of the Servos is not as intendet from me.
    The Servo should start moving normal fast and getting slower at the very last bit of movement until reaching the final position.


*/


#include <Servo.h>
//Switch will workwith 1 GND pin and 1 Digital Pin , no need of VCC pin :)
#define SwitchPin 3   // Digital Pin for Switch set on PCB
#define ledPin 3      // DingDingLED Eyes

//Servo Pins:
#define S1_PIN 12 // on PCB slot1
#define S2_PIN 5
#define S3_PIN 6
#define S4_PIN 7
#define S5_PIN 8
#define S6_PIN 9
#define S7_PIN 10

//Servo Objects:
Servo S1_SP; //Switch Pusher
Servo S2_LP; //Lid Pusher
Servo S3_FP; //Flag Pusher
Servo S4_ST; //Switch Turner (360° Servo)
Servo S5_SL; //Switch Level
Servo S6_IO; //Iris Opener
Servo S7_DP; //DingDing Pusher

//Start & End Servo Positions:

//Switch Pusher
int S1_StartPos = 130; //Arm In the box
int S1_MidPos = 100;   //Arm lurking
int S1_EndPos = 52;    //Arm pushed switch

// Lid Pusher
int S2_ClosePos = 30; // Lid Closed
int S2_OpenPos = 60;  // Lid Open

//Flag Pusher
int S3_StartPos = 30; // Pos in the Box
int S3_FlagPos_L = 60;
int S3_FlagPos_R = 90;

// Switch Turner
int S4_Turn_R = 30;  // Turn CW
int S4_Hold = 0;     // No turn
int S4_Turn_L = -30; // Turn CCW

//Switch Level
int S5_UpPos = 30;   //Switch Up
int S5_DownPos = 60; // Switch down

// Iris Opener
int S6_OpenPos = 30; // Iris open
int S6_ClosePos = 60; // Iris closed

// DingDing Pusher
int S7_InPos = 30; // DingDing In Box
int S7_OutPos = 60; //DingDing out of box


float movementProgress;
unsigned long previousMillis = 0;
bool busy_flag = false;



//---------------VOID SETUP---------------
void setup() {

  S1_SP.attach(S1_PIN);
  S2_LP.attach(S2_PIN);
  S3_FP.attach(S3_PIN);
  S4_ST.attach(S4_PIN);
  S5_SL.attach(S5_PIN);
  S6_IO.attach(S6_PIN);
  S7_DP.attach(S7_PIN);

  // Set all Servos on starting Position
  S1_SP.write(S1_StartPos);
  S3_FP.write(S3_StartPos);
  S2_LP.write(S2_ClosePos);
  S6_IO.write(S6_OpenPos); //Open Iris before Switch is up
  S4_ST.write(S4_Hold);
  S5_SL.write(S5_UpPos);
  S7_DP.write(S7_InPos);

  // Setup Debug Serial
  Serial.begin(9600);
  pinMode(SwitchPin, INPUT_PULLUP); // Set the SwitchPin as input with internal pull-up resistor
}


//---------------VOID LOOP---------------
void loop() {
  //DingDing_leds(500);
  //Jitter();
  Rand_Case_Switch();
}

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

// FUNCTION 2): For Rumbles the Lid in Idle
void Jitter() {

  if (busy_flag == LOW) {
    int pos = random(0, 180); // Random servo position
    S2_LP.write(pos);

    // Introduce jitter occasionally
    if (random(0, 100) < 10) { // Adjust probability as needed
      int originalPos = pos;
      int jitterRange = 10; // Jitter range in degrees
      int jitterTime = 500; // Jitter time in milliseconds

      // Create a rumbling effect
      for (int i = 0; i < 5; i++) { // Number of rumble cycles
        int jitter = random(-jitterRange, jitterRange);
        S2_LP.write(originalPos + jitter);
        delay(jitterTime);
        S2_LP.write(originalPos - jitter);
        delay(jitterTime);
      }

      S2_LP.write(originalPos); // Return to the original position
    }
  }
}

// Choooses Case if switch is pushed
void Rand_Case_Switch() {
  busy_flag = true;

  switch (generateRandomCase()) {
    case 1:
      Serial.println("Case 1");
      case1();
      break;
    case 2:
      Serial.println("Case 2");
      case2();
      break;
    case 3:
      Serial.println("Case 3");
      case3();
      break;
    case 4:
      Serial.println("Case 4");
      case4();
      break;
    case 5:
      Serial.println("Case 5");
      case5();
      break;
    case 6:
      Serial.println("Case 6");
      case6();
      break;
    case 7:
      Serial.println("Case 7");
      case7();
      break;
    default:
      // Default case (shouldn't be reached)
      Serial.println("Unknown case");
      break;
  }
  busy_flag = false; 
}

// Function to set Probability of the Cases
uint8_t generateRandomCase() {
  const uint8_t probabilities[] = {80, 1, 1, 1, 1, 1, 1}; // Adjust probabilities as needed
  const uint8_t cases[] = {1, 2, 3, 4, 5, 6, 7};
  const uint8_t randValue = random(100);
  uint8_t cumulativeProb = 0;
  for (uint8_t i = 0; i < 7; i++) {
    cumulativeProb += probabilities[i];
    if (randValue < cumulativeProb)return cases[i];
  }
  return 7;
}


// Servo Movement with an slowed down Endspeed
void MoveServoHuman(Servo &theServo, int targetPosition) {
  int currentPosition = theServo.read();

  int speed = 5;  // Initial speed of movement
  int minSpeed = 1;  // Minimum speed to ensure smooth final positioning

  while (currentPosition != targetPosition) {
    // Gradually decrease speed as servo approaches final position
    if (abs(targetPosition - currentPosition) < 10) {
      speed = max(minSpeed, speed - 10); //-1 Start
    }
    if (currentPosition < targetPosition) {
      currentPosition += speed;
      currentPosition = min(currentPosition, targetPosition);
    }
    else {
      currentPosition -= speed;
      currentPosition = max(currentPosition, targetPosition);
    }

    theServo.write(currentPosition);
    delay(10);  // Delay for smoother movement
  }
}

//---------------CASES---------------

// CASE 1: Simple Pusher
void case1() {
  MoveServoHuman (S1_SP, S1_EndPos); //-> The Arm pushes the Switch
  delay(500);  //--> Waits a few ms
  MoveServoHuman (S1_SP, S1_StartPos); //--> Moves Arm back in
}



// Case is Same as Case 1  but the arm goes out and stays longer aka. firmer on the switch
void case2() {
  S2_LP.write(S2_OpenPos);                 // Lid of the box opens (normal movement)
  delay(100);                              // wait for some ms
  MoveServoHuman (S7_DP, S7_OutPos);  // Ding Ding comes out of box
  delay(200);                             // wait for some ms
  MoveServoHuman (S1_SP, S1_EndPos); //-> The Arm pushes the Switch
  delay(2000);  //--> Waits a bit more than case 1
  MoveServoHuman (S1_SP, S1_StartPos); //--> Moves Arm back in
  MoveServoHuman (S7_DP, S7_InPos);  // Ding Ding goes back in box
  delay(200);                             // wait for some ms
  S2_LP.write(S2_ClosePos);                 // Lid of the box closes (normal movement)
}


//In this case the switch gets removed from the box and the iris closed
void case3() {
  S5_SL.write(S5_DownPos); //Switch gets moved "down" or in the box with no special movement
  delay(500);
  MoveServoHuman (S6_IO, S6_ClosePos); // Iris gets closed smothley
  delay(4000); // waits forever

  // --> Then Case 4 inside the box (Turns switch)
  MoveServoHuman (S6_IO, S6_OpenPos); // Iris gets opened again smothley
  delay(500);
  S5_SL.write(S5_UpPos); //Switch gets moved "up" agai
}

void case4() {
  S4_ST.write(S4_Turn_R); //The switch gets turned clockwise
  delay(1000); //Move Servo approx 1 sec until the Switch reached 180°
  S4_ST.write(S4_Hold); //Stop Servo
}

/* My two problems here to code:
  1) The Switch should always be mechanically turned alternating clockwise 180° and when this case occurs again counter clockwise (180°). So that the switch cabling doesn't get tangled up.
  How does such a case look like?
  Saeed's Response: Bro that's mechanical problem you can use brushes just like in DC motor to avoid the wires being rotated . It will not leave any effect at arduino it'll alsway consier as a switch as it is.

  2) Normally (in other cases) the switch gets pushed by the User and bushed back by the machine.
  In this "turning case" the switch gets pushed by the User but the machine only turns the switch phisicaly by 180° to solve the case.
  So does the system know again that busy_flag state has changed?
  Saeed's Response: Busy flag is just there for jitter function , you told that there must be an occasional jitter when device is not doing anything else. So
  this flag tell about if device is busy in another function or not.
*/


//In this case the box gives up... or supposes like
void case5() {
  S2_LP.write(S2_OpenPos);                 // Lid of the box opens (normal movement)
  delay(100);                              // wait for some ms
  MoveServoHuman (S7_DP, S7_OutPos);  // Ding Ding comes out of box
  delay(200);                             // wait for some ms¨
  MoveServoHuman (S3_FP, S3_FlagPos_R);  // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_L); // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_R);  // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_L); // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_R);  // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_L); // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_R);  // Flag waving from right to left...
  MoveServoHuman (S3_FP, S3_FlagPos_L); // Flag waving from right to left...

  //--> There is a smarter way to do this waving flag?

  // now suddenly the arm switches the switch and everything closes
  MoveServoHuman (S3_FP, S3_StartPos); // -> Flag goes back in
  MoveServoHuman (S1_SP, S1_EndPos); // -> The Arm pushes the Switch
  delay(500);  //--> Waits a few ms
  MoveServoHuman (S1_SP, S1_StartPos); // --> Moves Arm back in
  MoveServoHuman (S7_DP, S7_InPos);   // Ding Ding goes back in box
  delay(200);                             // wait for some ms
  S2_LP.write(S2_ClosePos);                 // Lid of the box closes (normal movement)
}

void case6() {
  //TBD by me
}

void case7() {
  unsigned long currentTime = millis();

}

void restoreservos(){ // This func. is used to restore servo positions to their start when intended

  S1_SP.write(S1_StartPos);
  S3_FP.write(S3_StartPos);
  S2_LP.write(S2_ClosePos);
  S6_IO.write(S6_OpenPos); //Open Iris before Switch is up
  S4_ST.write(S4_Hold);
  S5_SL.write(S5_UpPos);
  S7_DP.write(S7_InPos);
}

This. It just tells you the last value you wrote to the servo.

due this, if box is starting it must rotate the switch to some known reference position

Hey guys

Thank you for the first replys.
So as @paulpaulson mentioned I cut all the fancy stuff and start over with the basis code. Posted below. Note: This Code does the job perfectly fine. When I flick the switch --> Case 1 gets chosen (Since I increased the probability on case 1) and in this Case 1 the servo flicks the switch back. Starting over again as soon I flick it.

Here is the Code I would like to start with since the first I posted code has too much stuff in it.

/*
   Changelog:
   V0 - First Draft Code by Saeed
   V1 - Changes done by Nik:
      - Changed some Servo Position names and Start and end Positions
      - Excluded the LED Eyes function for now. I will just turn the LED on when DingDing gets out of the box to S7_OutPos
      - "Deleted" the Cases. I will set them once I have some time. So lets work for now only with case 1. I made the example what should happen in Cas1
   V1.1
      - I did it like this and this worked well with the switch (On/off Switch) and the code like:
      ...
      Switch Pin 13;
      ...
    The Servo should start moving normal fast and getting slower at the very last bit of movement until reaching the final position.


*/
#include <Servo.h>

//Switch will workwith 1 GND pin and 1 Digital Pin , no need of VCC pin :)
#define SwitchPin 3   // Digital Pin for Switch set on PCB
// #define ledPin 5      // DingDingLED Eyes

unsigned long previousMillis = 0;
int ledState = LOW;

int lastSwitchState = LOW; // Variable, um den letzten Zustand des Schalters zu speichern


//Servo Pins:
#define S1_PIN 12 // on PCB slot1
#define S2_PIN 11
#define S3_PIN 10
#define S4_PIN 9
#define S5_PIN 8
#define S6_PIN 7
#define S7_PIN 6

//Servo Objects:
Servo S1_SP; //Switch Pusher
Servo S2_LP; //Lid Pusher
Servo S3_FP; //Flag Pusher
Servo S4_ST; //Switch Turner (360° Servo)
Servo S5_SL; //Switch Level
Servo S6_IO; //Iris Opener
Servo S7_DP; //DingDing Pusher

//Start & End Servo Positions:

//Switch Pusher
int S1_StartPos = 130; //FIX: 130 Arm In the box
int S1_MidPos = 100;   //Arm lurking
int S1_EndPos = 52;    //FIX:52 Arm pushed switch

// Lid Pusher
int S2_ClosePos = 30; // Lid Closed
int S2_OpenPos = 60;  // Lid Open

//Flag Pusher
int S3_StartPos = 150; //FIX: 150 - Pos in the Box 
int S3_FlagPos_L = 30;  //FIX: 30
int S3_FlagPos_R = 90;  //FIX: 90

// Switch Turner
int S4_Turn_R = 60;  //FIX:  60 Turn CW
int S4_Hold = 90;    //FIX:  90 No turn
int S4_Turn_L = 120; //FIX:  120 Turn CCW

//Switch Level
int S5_UpPos = 38;     //FIX: 38 Switch Up
int S5_DownPos = 115; //FIX: 115 Switch down

// Iris Opener
int S6_OpenPos = 148; //FIX: 148 Iris open
int S6_ClosePos = 68; //FIX: 68 Iris closed

// DingDing Pusher
int S7_InPos = 160; //FIX: 160 DingDing In Box
int S7_OutPos = 90; //FIX: 90 DingDing out of box


unsigned long startTime;


//---------------VOID SETUP---------------
void setup()
{
// Set all Servos on starting Position
  S1_SP.write(S1_StartPos);
  S3_FP.write(S3_StartPos);
  S2_LP.write(S2_ClosePos);
  S6_IO.write(S6_OpenPos); //Open Iris before Switch is up
  S4_ST.write(S4_Hold);
  S5_SL.write(S5_DownPos);
  S7_DP.write(S7_InPos);

  S1_SP.attach(S1_PIN);
  S2_LP.attach(S2_PIN);
  S3_FP.attach(S3_PIN);
  S4_ST.attach(S4_PIN);
  S5_SL.attach(S5_PIN);
  S6_IO.attach(S6_PIN);
  S7_DP.attach(S7_PIN);

 int lastSwitchState = LOW;

  // Setup Debug Serial
  Serial.begin(9600);
  pinMode(SwitchPin, INPUT_PULLUP); // Set the SwitchPin as input with internal pull-up resistor
  startTime = millis();

}


//---------------VOID LOOP---------------
void loop()
{

  // TestServoPos();
  
  
  int currentSwitchState = digitalRead(SwitchPin);

  // Check if switch is switched
  if (currentSwitchState != lastSwitchState) {
    if (currentSwitchState == HIGH) {
      Rand_Case_Switch(); // Starts to choose a case
    }
  }
  
}

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

// FUNCTION 1): Move Servo normal to angle
void Moveservo_check(Servo &theServo, int angle)
{
  theServo.write(angle);
}


// FUNCTION 2): Servo Human Move





// FUNCTION 3):   


// FUNCTION 3:
void Rand_Case_Switch()
{
  int caseNumber = generateRandomCase();
  switch (caseNumber) {
    case 1:
      // Code for Case 1
      Serial.println("Case 1");
      case1();
      break;

    case 2:
      // Code for Case 2
      Serial.println("Case 2");
      case2();
      break;

    case 3:
      // Code for Case 3
      Serial.println("Case 3");
      case3();
      break;

    case 4:
      // Code for Case 4
      Serial.println("Case 4");
      case4();
      break;

    case 5:
      // Code for Case 5
      Serial.println("Case 5");
      case5();
      break;

    case 6:
      // Code for Case 6
      Serial.println("Case 6");
      case6();
      break;

    case 7:
      // Code for Case 7
      Serial.println("Case 7");
      case7();
      break;

    default:
      // Default case (shouldn't be reached)
      Serial.println("Unknown case");
      break;
  }


}

//FUNCTION 5): TEST all Servos on starting Position and End Position

void TestServoPos() {

 // Colision preventing
  S3_FP.write(S3_StartPos);
  S2_LP.write(S2_OpenPos);
  
//-TEST- SwitchPusher
  S1_SP.write(S1_StartPos);
  delay(1000);
  S1_SP.write(S1_EndPos);
  delay(1000);
  S1_SP.write(S1_StartPos);
  delay(1000);
  
//-TEST- FlagPusher
  S3_FP.write(S3_StartPos);
  delay(1000);
  S3_FP.write(S3_FlagPos_L);
  delay(500);
  S3_FP.write(S3_FlagPos_R);
  delay(500);
  S3_FP.write(S3_FlagPos_L);
  delay(500);
  S3_FP.write(S3_FlagPos_R);
  delay(1000);
  S3_FP.write(S3_StartPos);
  delay(1000);
  
//-TEST- DingDingPusher
  S7_DP.write(S7_InPos);
  delay(1000);
  S7_DP.write(S7_OutPos);
  delay(1000);
  S7_DP.write(S7_InPos);
  delay(1000);

//-TEST- SwitchTurner
  S4_ST.write(S4_Turn_R);
  delay(500);
  S4_ST.write(S4_Turn_L);
  delay(500);
  S4_ST.write(S4_Hold);
  delay(1000);

//-TEST- SwitchLevel
  S5_SL.write(S5_UpPos);
  delay(1000);
  S5_SL.write(S5_DownPos);
  delay(1000);
  S5_SL.write(S5_UpPos);
  delay(1000);

//-TEST- Iris
  S5_SL.write(S5_DownPos);
  delay(1000);
  S6_IO.write(S6_OpenPos);
  delay(1000);
  S6_IO.write(S6_ClosePos);
  delay(1000);
  S6_IO.write(S6_OpenPos);
  delay(1000);
  S6_IO.write(S6_ClosePos);
  delay(1000);
   S6_IO.write(S6_OpenPos);
  delay(1000);

}

// FUNCTION 6) to set Probability of the Cases
int generateRandomCase() {
  float probabilities[] = {0.8, 0.8, 0.01, 0.01, 0.01, 0.01, 0.01}; // Adjust probabilities as needed
  int cases[] = {1, 2, 3, 4, 5, 6, 7};
  float randValue = random(100) / 100.0;

  float cumulativeProb = 0.0;
  for (int i = 0; i < sizeof(probabilities) / sizeof(float); i++) {
    cumulativeProb += probabilities[i];
    if (randValue < cumulativeProb) {
      return cases[i];
    }
  }

  // Fallback case (shouldn't be reached)
  return cases[sizeof(cases) / sizeof(int) - 1];
}

// FUNCTION 7) // Restore Servo Positions
void restoreservos() // This func. is used to restore servo positions to their start when intended
{
  S1_SP.write(S1_StartPos);
  S3_FP.write(S3_StartPos);
  S2_LP.write(S2_ClosePos);
  S6_IO.write(S6_OpenPos); //Open Iris before Switch is up
  S4_ST.write(S4_Hold);
  S5_SL.write(S5_DownPos);
  S7_DP.write(S7_InPos);
}


//----------------------CASES-----------------------------------------------

// CASE 1: Simple Pusher
void case1() {
  Moveservo_check (S1_SP, S1_EndPos); //-> The Arm pushes the Switch
  delay(500);  //--> Waits a few ms
  Moveservo_check (S1_SP, S1_StartPos); //--> Moves Arm back in
}

// Case is Same as Case 1  but the arm goes out and stays longer aka. firmer on the switch
void case2() {
   S2_LP.write(S2_OpenPos);                 // Lid of the box opens (normal movement)
   delay(100);                              // wait for some ms
   Moveservo_check (S7_DP, S7_OutPos);  // Ding Ding comes out of box
   delay(200);                             // wait for some ms
   Moveservo_check (S1_SP, S1_EndPos); //-> The Arm pushes the Switch
   delay(2000);  //--> Waits a bit more than case 2
   Moveservo_check (S1_SP, S1_StartPos); //--> Moves Arm back in
   Moveservo_check (S7_DP, S7_InPos);  // Ding Ding goes back in box
   delay(200);                             // wait for some ms
   S2_LP.write(S2_ClosePos);                 // Lid of the box closes (normal movement)
}

//In this case the switch gets removed from the box and the iris closed
void case3() {
  //TBD by me
}

void case4() {
  //TBD by me
}


//In this case the box gives up... or supposes like
void case5() {
  //TBD by me
}

void case6() {
  //TBD by me
}

void case7() {
  //TBD by me
}

I also want to tackle the upgrades now one after another so, if you like, I would prefer to tackle the problem with the switch states.

here a video what I mean by "turning the switch": HAHAHA my first Youtube Upload in my life :stuck_out_tongue:

So as you see, one solution (case 4, not coded jet) of the Uselessbox is to turn the switch physically and so solving the only problem it always wants to solve: Having the switch flicked on the right side.

This introduces now the problem: Once the switch is turned the flicked side is a new one and the code should work as before but with the new side of the switch being oposed. I hope this helps for the understanding?
To the states of the switch @Paul_KD7HB : yes I'm aware of this but with the code above I have no problems working just with "high" and "low"

It doesn't compile. Just a matter of adding a final closing brace to setup, but in case you have other differences, please post the version that works.

sorry it compiles now. I added a function to test all the servo Start and end Pos

Not really. Is the switchPin supposed to change after the flip occurs? Which is the flip servo?

No switch pin is not to changed. The Servo that flips the switch back is S1, the servo that turns the switch is S4 (not implemented jet in the code)

I try to make an example:

  1. Standard Useless box behavior:
  • Starting Arduino: Switch is in the right position on: LOW \ HIGH
  • User pushes switch: LOW / HIGH -> Case1>Servo1 flicks switch back on: LOW \ HIGH
  • This could go on forever since this is the main task of the uselessbox
  1. Sophisticated useless Box behavior (with turning switch by 180 degrees)
  • Starting Arduino: Switch is in the assumed right position on: LOW \ HIGH
  • User pushes switch: LOW / HIGH -> Case1>Servo1 flicks switch back on: LOW \ HIGH
  • User pushes switch: LOW / HIGH -> Case4>Servo4 turns switch 180° back BUT: HIGH \ LOW
  • User pushes switch again: HIGH / LOW -> Case1>Servo1 flicks switch back on: HIGH \ LOW
    And now generally talking Case 4 could happen again and the switch is turned physically again.
    So how can I solve in Code the problem of a turning switch (case4) and with this how can the uselessbox start with a random switch position (HIGH or LOW) but ready to switch for the user, dependig on what "state" the Uselssbox was turned of.

See post #3.

Sorry I don't see how this solves my problem.

I'm afraid the problem mentioned is not at all clear (to me at least).

What should happen when case 4 is picked by the randomizer? What about twice in a row?

Regarding servo four - is it controllable through 360 degrees of position or is it a continuous servo that can rotate forever?

I suspect that what you need here is simple enough, if you can describe the requirements well.

hm so it's all about the changing "initial" state of the switch when beeing turned in case 4:
Servo 4 is a 360° Servo which would run for, lets say, 2 seconds and turns the switch CCW or CW like seen in the Video i posted. Case for would look like this:

void case4(){
    S4_ST.write(S4_Turn_R); //The switch gets turned clockwise
    delay(1000); //Move Servo approx 1 sec until the Switch reached 180°  
    S4_ST.write(S4_Hold); //Stop Servo
  }

As you mentioned the Case 4 could be activated again, as soon as the user flicks the switch again.
BUT again in my most recent post I think I really show whats the matter with the turned switch and how the LOW and HIGH states get physically turned in case 4. This should be considered somehow in the code. Otherwise once the switch is turned, the box always wants to set back the switch since it doesn't know that the switch is "flicked" aka. turned.

Can you just use case1 code to put the switch back and then spin the 180 degrees?

Or spin & then switch .

I wondered where you could use the two state variables in loop, but they aren’t used anywhere else.

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