Moving servo motors at once then return to their original position at once as well

Hello! Im just a beginner. Can you help me with my code? I have a Python code that sends a command/data to my Arduino code to move the 3 servo motors under a condition. My program goes like this: First, the user will input a number 1-5 then it will store it in a list. When the number falls into the same index as their number, the number/s will be popped up then the servo motors that correspond to them will move to 180 degree then will return to their original position(90 degree). For example: [5,4,3, None, None] since the number 3 is in the same index (index + 1) as its number, it will be popped up automatically like [5,4, None, None, None] then the servo motor that corresponds to it will move. Note that Servo 1 is for number 3, Servo 2 is for number 4, Servo 3 is for number 5. There are no servo motors for number 1 and 2.

Now, if there are multiple numbers that are being popped up at the same time, for example, [5, 3, 3, 5, 5], since the number 3 and number 5 are on the same index, they will pop up at the same time, [5, 3, None, 5, None]. And because they popped up at the same the, the servo motors that correspond to them (servo 1 and servo 3) should move to 180 degree all at once, they will move at the same time, then they will go back to their original position also at the same time.

I have this simple code that will rotate the servo motors at once when necessary but my problem is, I cannot implement the code that will make them return to their original position at once if there are multiple numbers that are being popped up. Can you help me with what will be the code for that? I tried to fix this but as there are multiple numbers that are being popped up, they are not moving at once, they are moving one by one.
Here's my Python code that sends an command/data to my Arduino code:

import serial
import time
ser = serial.Serial('COM3', 9600)  # Replace 'COM3' with the port name of your Arduino board

def reverseFindIndex(element, array:list) -> int:
    for i in range(len(array), 0, -1):
        if array[i-1]==element:
            return i-1


classified_array = [
    None, None, None, None, # bins 1, 2, 3, 4
    None, # bin 5
]

while True:
    ## classification
    camera_output = int(input("Classification: "))

    classified_array.insert(0, camera_output)
    classified_array.pop()

    ## Before
    print(f'Before: {classified_array}', end='\n\n')

    ## checks if marked items is equal to the target bin
    for c in classified_array:
        target_bin = reverseFindIndex(c, classified_array) + 1
        if c == target_bin:                     # if the inputted numbers are on the same index
            classified_array[target_bin-1] = None
            print(f'Tossed at bin {target_bin}!', end='\n')
            ser.write(str(target_bin).encode())  # send the bin number to Arduino
    
    ## After
    print(f'After: {classified_array}', end='\n\n')

And here's my Arduino code

#include <Servo.h>

Servo servo1, servo2, servo3;

void setup() {
  servo1.attach(2);
  servo2.attach(3);
  servo3.attach(4);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    int bin_number = Serial.read() - '0'; // convert ASCII to int

    if (bin_number == 3) {
      servo1.write(180);
    }

    if (bin_number == 4) {
      servo2.write(180);
    }

    if (bin_number == 5) {
      servo3.write(180);
    }
  }
}

Note: I removed the code that make them return to their original position coz it failed. I am seeking help on what should I do or add to my code to achieve my goal. I hope you help me.

What does "then" mean here? How long should they stay at 180° before they move to 90°? What should trigger the return? Should it be a fixed amount of time?

When the servo motor/s already reached 180 degrees, it/they will return to 90 asap. To give context, it is for sorting that pushes an object.

What servo do you have?

Normal servos do not communicate when they reach position, so people often give them time to travel before giving them new commands.

Can you help me? It is like a swipe that the servo motor/s will rotate back and forth. But in this case, it has a condition as I mentioned above. My problem is, if there are multiple numbers that are being popped up at the same time, the servo motors that are corresponding to them should move back and forth (to 180 then back to 90), but I cant implement that in my code.

I am using SG92R servo motor.

Kindly watch this youtube video because this is what I am trying to do with my sorter. As you can see, the servo motors can move at the same time to push the tomato
https://www.youtube.com/watch?v=h0-NS3z-EXo

I bet the folks in that video use something like the built-in example Digital/Debounce, Digital/StateChangeDetection or Digital/BlinkWithoutDelay to schedule code like:

void returnAllServos(void){
   servo1.write(90);
   servo2.write(90);
   servo3.write(90);
}

Looking at that video, I would save the mills() that you last received a serial input, and use the blink without delay trick to return all the servos to position an interval of 1000ms later.

Hello Newbie1.1.1

Consider this simplifcation:

#include <Servo.h>

Servo servo1, servo2, servo3;

void setup() {
  servo1.attach(2);
  servo2.attach(3);
  servo3.attach(4);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0) {
    int bin_number = Serial.read() - '0'; // convert ASCII to int

    (bin_number == 3) ? servo1.write(180) : servo1.write(90);
    (bin_number == 4) ? servo2.write(180) : servo2.write(90);
    (bin_number == 5) ? servo3.write(180) : servo3.write(90);
  }
}

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

1 Like

Closing them when they receive a new bin command could be good, but in this case, new commands (even whitespace) would abort the servo moves from the previous commands.

How to implement that in my code? How to modify my code?

Hi! Thank you for your help. I tried that in my code but unfortunately, it didn't work. When I inputted numbers and there are numbers that are being popped up at the same time, the servo motors that are corresponding to them are not moving at the same time. And when only one number are being popped up, the servo motor that are corresponding to it rotates to 180 but it didn't return to its original position as soon as it reach the 180, it should go back asap in their original position as they reach the 180

Can you help me sir to modify my code to accomplish this?

How to do that sir in my code? Sorry, I'm just a beginner in Arduino, that's why I'm seeking for a help

I hope you help me sir

Please post your latest code

Hello Newbie1.1.1

Consider this corrected simplifcation:

#include <Servo.h>

Servo servo1, servo2, servo3;

void setup() {
  servo1.attach(2);
  servo2.attach(3);
  servo3.attach(4);
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0)
  {
    int bin_number = Serial.read();
    if (bin_number != '\n')
    {
      bin_number = bin_number - '0'; // convert ASCII to int

      (bin_number == 3) ? servo1.write(180) : servo1.write(90);
      (bin_number == 4) ? servo2.write(180) : servo2.write(90);
      (bin_number == 5) ? servo3.write(180) : servo3.write(90);
    }
  }
}

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

Hi sir,the code in my post is the latest one, i didnt update it yet. The suggested code that was replied to me is not working well.

Please describe how it falls short of your expectations (apart from "it's too long" and "it has obvious anti-plagiarism built-in")

To your code, I'd add a global variable to remember the millis() when things last went out of position:

unsigned long lastOutOfPositionMs = 0; // global variable to remember out-of-position time across loop()s.

then within your command reading code, I'd set that to the last time you moved things:

  if (Serial.available() > 0) {
    int bin_number = Serial.read() - '0'; // convert ASCII to int

    if (bin_number == 3) {
      servo1.write(180);
      lastOutOfPositionMs= millis();
    }

    if (bin_number == 4) {
      servo2.write(180);
      lastOutOfPositionMs= millis();
    }

    if (bin_number == 5) {
      servo3.write(180);
      lastOutOfPositionMs= millis();
    }

Then I'd write a test within loop() to see if enough time has passed in order to reset things:

  // ...
  if(millis() - lastOutOfPositionMs > 500){ // set long enough to allow servos to make it to position.
     returnAllServos();
  }
  //...

If your system runs as fast as the video, these sorts of changes should be enough. If things happen much faster or chaotically, you might need more code to protect from moving while the servos are out of position, or to track the times for the individual servos.

Of if you have code that works more like the video, you might just call returnAllServos() when you would do whatever moves the belt.

Hi sir, thank you so much for your help. I tried the code that you provided and it works. The servo motors are now moving back and forth at the same time if there are multiple numbers are being popped up at the same time. Thank you so much for your help, sir. I appreciate it.