Troubleshooting SG90 Servo twitching, buzzing and overheating issues in multi-servo arduino project

Hello everyone,

I’ve built an Arduino-based robot, but I’m facing serious issues with the servos, especially the SG90 servos. They are shaking or twitching a lot, even when there is no load on them. I’ve read online that it might help to turn off the servo signal once the target position is reached. Another problem is that the servos are buzzing and getting warm. Since I’m controlling more than four servos simultaneously, this issue seems to be worsened.

It could be that a non-constant PWM signal is being generated, or perhaps two timers are interfering with each other, causing the PWM signal to become distorted. I’ve also read that servos have a certain "deadband" range, and the PWM signal should stay within this tolerance to avoid jittering. However, I’m not sure how to set this deadband or where to read it.

I want the servos to only be activated when I control them via the app I created with MIT App Inventor. It’s possible that interrupts are overlapping, causing the jittering, but I have no idea how to implement this. I am a complete beginner when it comes to programming, and I don’t have any experience with projects like this. This is why I’m having a lot of difficulty understanding and editing the code.

It would be really helpful if someone could check my code and provide very detailed, step-by-step instructions on what changes need to be made and how to implement them. I still don’t understand much of the subject, so I would greatly appreciate detailed help.

This project should be finished by January 23rd, so it’s quite urgent. I hope someone can help me with this issue so I can complete the project on time.

Thank you in advance!

This is my code:

#include <SoftwareSerial.h>//importiert die SoftwareSerial-Bibliothek, um serielle Kommunikation auf anderen Pins als den Standortpins durchzuführen
#include <Servo.h>// importiert die Servo-Bibliothek, die für die Steuerung von Servomotoren genutzt werden

Servo servo01;
Servo servo02;
Servo servo03;
Servo servo04;
Servo servo05;
Servo servo06;// jede Zeile definiert ein Servo-Objekt, das zum Steuern eines Servomotors verwendet wird

SoftwareSerial Bluetooth(13 , 12); // erstellt eine SoftwareSerial-Verbindung auf den Pins 13(TX) und 12 (RX), um mit den HC-05-Bluetooth-Modul zu kommunizieren
int servo1Pos, servo2Pos, servo3Pos, servo4Pos, servo5Pos, servo6Pos; // speichert die aktuelle Position jedes Servos
int servo1PPos, servo2PPos, servo3PPos, servo4PPos, servo5PPos, servo6PPos; // previous position
int servo01SP[50], servo02SP[50], servo03SP[50], servo04SP[50], servo05SP[50], servo06SP[50]; // Array für jeden Servo, um bis zu 50 Positionen zu speichern
int speedDelay = 20;// Geschwindigkeit der Servo-Bewegung (Verzögerung zwischen den Bewegungen)
int index = 0;// Variable für den Index der gespeicherten Positionen im Array
String dataIn = "";// Variable zum Speichern von Daten, die über Bluetooth empfangen werden
void setup() {// diese Funktion wird nur einmal ausgeführt

Serial.begin(9600);// initialisiert die serielle Kommunikation mit einer Baudrate von 38400

  
  servo01.attach(5);// verbindet jeden Servo mit einem bestimmten Pin am Elegoo
  servo02.attach(6);
  servo03.attach(7);
  servo04.attach(8);
  servo05.attach(9);
  servo06.attach(10);
  Bluetooth.begin(9600); // initialisiert die Bluetooth-Kommunikation mit einer Baudrate von 9600
  Bluetooth.setTimeout(1);// setzt ein Timeout von 1ms für die Bluetooth-Kommunikation
  delay(20);// wartet 20ms, um die initiale Verbindung zu stabilisieren
  
  servo1PPos = 90;//setzt die Anfangsposition jedes Servos auf 90°
  servo01.write(servo1PPos);
  servo2PPos = 90;
  servo02.write(servo2PPos);
  servo3PPos = 90;
  servo03.write(servo3PPos);
  servo4PPos = 90;
  servo04.write(servo4PPos);
  servo5PPos = 90;
  servo05.write(servo5PPos);
  servo6PPos = 90;
  servo06.write(servo6PPos);
  Serial.println("init ok");
}

void loop() {// diese Funktion läuft kontinuierlich
  // put your main code here, to run repeatedly:
  // Check for incoming data
  if (Bluetooth.available() > 0) {// prüft, ob Daten vom Bluetooth-Modul empfangen wurden. Bluetooth.available()gibt die Anzahl der empfangenden Zeichen zurück
    dataIn = Bluetooth.readString();  // liest Daten als String und speichert sie in der Variablen data.In
    Serial.println("bluetooth ok");// gibt "Bluetooth ok" auf dem seriellen Monitor aus, um anzuzeigen, dass Daten erfolgreich empfangen wurden
    Serial.println(dataIn);//gibt die empfangenen Daten (dataIn) aus. printIn sorgt dafür, dass die Ausgabe in einer neuen Zeile endet

    // If "Waist" slider has changed value - Move Servo 1 to position
    if (dataIn.startsWith("s1")) {// prüft, ob der empfangene  Befehl (dataIn) mit "s1" beginnt. Dies weist darauf hin, dass es sich um einen Befehl für Servo1 handelt
      String dataInS = dataIn.substring(2, dataIn.length()); // extrahiert die Zahl(die Zielpositions des Servos) aus dem String
      servo1Pos = dataInS.toInt();  // konvertiert den extrahierten String in einen Ganzzahlwert und speichert ihn in der Variablen servo01Pos
      Serial.print("Servo 1: ");// gibt "Servo1" auf dem seriellen Monitor aus, um anzuzeigen, dass ein Befehl für Servo1 empfangen wurde 
      Serial.println(servo1Pos); // gibt die Zielposition von Servo1 auf dem seriellen Monitor aus
      
      // If previous position is bigger then current position
      if (servo1PPos > servo1Pos) {// prüft, ob die neue Zielposition (servo01Pos) größer ist als die aktuelle Position (servo01PPos).Wenn ja, bedeutet dies, dass sich der Servo nach vorne bewegen muss
        for ( int j = servo1PPos; j >= servo1Pos; j--) {   // Schleife, die den Servo Schritt für Schritt von der aktuellen Position (servo01PPos) zur Zielposition(servo01Pos) bewegt
          servo01.write(j);// sendet Winkel j an den Servo. Der Servo wird auf die entsprechende Position bewegt
          delay(20);    // wartet 20ms zwischen den Schritten. Dadurch wird die Bewegung des Servos langsamer und kontrollierter
        }
      }
      // If previous position is smaller then current position
      if (servo1PPos < servo1Pos) {// wenn die Zielposition(servo01Pos) kleiner ist als die aktuelle Position (servo01PPos), bewegt sich der Servo rückwärts
        for ( int j = servo1PPos; j <= servo1Pos; j++) {   // Schleife bewegt den Servo schrittweise rückwärts von der aktuellen Position zur Zielposition
          servo01.write(j);// sendet Winkel j an den Servo. Der Servo bewegt sich entsprechend
          delay(20);
        }
      }
      servo1PPos = servo1Pos;   // aktualisiert die aktuelle Position des Servos (servo01Pos) und speichert sie als vorherige Position (servo01PPos). Dies stellt sicher, dass die zukünftige Bewegung von der richtigen Starposition ausgeht

    }
    // Der gleiche Prozess folgt für alle anderen Servos, allerdings mit anderen Variablen-> der Code funktioniert nach dem gleichen Muster
      // Move Servo 2
    if (dataIn.startsWith("s2")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo2Pos = dataInS.toInt();
      Serial.print("Servo 2: ");
      Serial.println(servo2Pos);
      if (servo2PPos > servo2Pos) {
        for ( int j = servo2PPos; j >= servo2Pos; j--) {
          servo02.write(j);
          delay(50);
        }
      }
      if (servo2PPos < servo2Pos) {
        for ( int j = servo2PPos; j <= servo2Pos; j++) {
          servo02.write(j);
          delay(50);
        }
      }
      servo2PPos = servo2Pos;
    }
      // Move Servo 3
    if (dataIn.startsWith("s3")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo3Pos = dataInS.toInt();
      Serial.print("Servo 3: ");
      Serial.println(servo3Pos);
      if (servo3PPos > servo3Pos) {
        for ( int j = servo3PPos; j >= servo3Pos; j--) {
          servo03.write(j);
          delay(30);
        }
      }
      if (servo3PPos < servo3Pos) {
        for ( int j = servo3PPos; j <= servo3Pos; j++) {
          servo03.write(j);
          delay(30);
        }
      }
      servo3PPos = servo3Pos;
    }
     // Move Servo 4
    if (dataIn.startsWith("s4")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo4Pos = dataInS.toInt();
      Serial.print("Servo 4: ");
      Serial.println(servo4Pos);
      if (servo4PPos > servo4Pos) {
        for ( int j = servo4PPos; j >= servo4Pos; j--) {
          servo04.write(j);
          delay(30);
        }
      }
      if (servo4PPos < servo4Pos) {
        for ( int j = servo4PPos; j <= servo4Pos; j++) {
          servo04.write(j);
          delay(30);
        }
      }
      servo4PPos = servo4Pos;
    }
    // Move Servo 5
    if (dataIn.startsWith("s5")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo5Pos = dataInS.toInt();
      Serial.print("Servo 5: ");
      Serial.println(servo5Pos);
      if (servo5PPos > servo5Pos) {
        for ( int j = servo5PPos; j >= servo5Pos; j--) {
          servo05.write(j);
          delay(30);
        }
      }
      if (servo5PPos < servo5Pos) {
        for ( int j = servo5PPos; j <= servo5Pos; j++) {
          servo05.write(j);
          delay(30);
        }
      }
       servo5PPos = servo5Pos;
    }
    // Move Servo 6
    if (dataIn.startsWith("s6")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo6Pos = dataInS.toInt();
      Serial.print("Servo 6: ");
      Serial.println(servo6Pos);
      if (servo6PPos > servo6Pos) {
        for ( int j = servo6PPos; j >= servo6Pos; j--) {
          servo06.write(j);
          delay(30);
        }
      }
      if (servo6PPos < servo6Pos) {
        for ( int j = servo6PPos; j <= servo6Pos; j++) {
          servo06.write(j);
          delay(30);
        }
      }
      servo6PPos = servo6Pos; 
    }
     // If button "SAVE" is pressed
    if (dataIn.startsWith("SAVE")) {// prüft, ob der empfangene Befehl "SAVE"ist. Dies bedeutet, dass die aktuellen Servo-Positionen gespeichert werden sollen
      Serial.println("SAVE");//gibt "SAVE" auf dem seriellen Monitor aus, um zu bestätigen, dass der Befehl empfangen wurde
      servo01SP[index] = servo1PPos;  // speichert die aktuellen Positionen der Servos (servo01PPos bis servo06PPos) in den Arrays servo01SP,servo02SP, etc.. Der Index gibt an, an welcher Stelle die Positionen im Array gespeichert werden
      servo02SP[index] = servo2PPos;
      servo03SP[index] = servo3PPos;
      servo04SP[index] = servo4PPos;
      servo05SP[index] = servo5PPos;
      servo06SP[index] = servo6PPos;
      index++;                        // erhöht den Index, sodass die nächste gespeicherte Position in einem neuen Slot des Arrays landet
    }
    // If button "RUN" is pressed
    if (dataIn.startsWith("RUN")) {//prüft, ob der empfangende Befehl "Run" ist. Dieser Befehl weist das Programm an, die gespeicherten Schritte auszuführen
      Serial.println("RUN");//gibt "RUN" auf dem seriellen Monitor aus, um zu bestätigen, dass der Befehl empfangen wurde
      runservo();  // ruft die Funktion runServo() auf, die die gespeicherten Schritte abarbeitet
    }
    // If button "RESET" is pressed
    if ( dataIn == "RESET") {//prüft, ob der empfangende Befehl "RESET" ist. Dieser Befehl löscht alle gespeicherten Schritte
      Serial.println("RESET");// gibt "RESET" auf dem seriellen Monitor aus, um zu bestätigen, dass der Befehl empfangen wurde
      memset(servo01SP, 0, sizeof(servo01SP)); // setzt alle Werte in den Arrays servo01SP bis Servo06SP auf 0. Dadurch werden die gespeicherten Schritte gelöscht
      memset(servo02SP, 0, sizeof(servo02SP));
      memset(servo03SP, 0, sizeof(servo03SP));
      memset(servo04SP, 0, sizeof(servo04SP));
      memset(servo05SP, 0, sizeof(servo05SP));
      memset(servo06SP, 0, sizeof(servo06SP));
      index = 0;  // setzt den Index auf 0 zurück, sodass neue Schritte wieder ab der ersten Position im Array gespeichert werden
    }
  }
}
// Automatic mode custom function - run the saved steps
void runservo() {// definiert die Funktion, die die gespeicherten Schritte wiederholt ausführt, bis der "RESET"-Befehl empfangen wird
  while (dataIn != "RESET") {   // führt Schleife kontinuierlich aus, solange der "RESET"-Befehl niicht empfangen wird
    for (int i = 0; i <= index - 2; i++) {  // durchläuft alle gespeicherten Schritte
      if (Bluetooth.available() > 0) {      // prüft, ob neue Daten über Bluetooth empfangen wurden
        dataIn = Bluetooth.readString();// liest die empfangenen Daten
        if ( dataIn == "PAUSE") {           // prüft, ob der "PAUSE"-Befehl empfangen wurde. Wenn ja, pausiert die Ausführung
          while (dataIn != "RUN") {         // wartet, bis der "RUN"-Befehl empfangen wird, um die Ausführung fortzusetzen
            if (Bluetooth.available() > 0) {
              dataIn = Bluetooth.readString();
              if ( dataIn == "RESET") {   // wenn der "RESET"-Befehl während der Pause empfangen wird, bricht die Schleife ab  
                break;
              }
            }
          }
        }
        // If speed slider is changed
        if (dataIn.startsWith("ss")) {//überprüft, ob der empfangende String (dataIn) mit den Buchstaben "ss" beginnt 
          String dataInS = dataIn.substring(2, dataIn.length());//schneidet die Zeichenkette so zu, dass nur die Zahl nach dem ss übrig bleibt
          speedDelay = dataInS.toInt(); // wandelt String in eine Ganzzahl und speichert diesen Wert in speedDelay -> dieser Wert wird später genutzt, um die Geschwindigkeit für die Bewegung der Servos festzulegen
        }
      }
      // Servo 1
      if (servo01SP[i] == servo01SP[i + 1]) {//überprüft, ob die aktuelle Servo-Position (servo01SP[i]) gleich der nächsten Position (servo01SP[i + 1]) ist
        Serial.println("Servo 1 Position: Kein Wechsel"); // gibt eine Nachricht auf dem seriellen Monitor aus, um anzuzeigen, dass kein Positionswechsel stattfindet
        // Elegoo sendet jede Servoposition zeilenweise an seriellen Monitor-> jede Position ist klar und getrennt sichtbar
      }
      if (servo01SP[i] > servo01SP[i + 1]) {// überprüft, ob die aktuelle Position größer ist als die nächste Position -> trifft dies zu, muss der Servomotor seine Position schrittweise verringern
        for ( int j = servo01SP[i]; j >= servo01SP[i + 1]; j--) {//startet Schleife, die den Servo von seiner aktuellen Position bis zur Zielposition in Einzelschritten bewegt, j-- verringert die Position in jedem Schritt um 1
          servo01.write(j);// bewegt Servo zu der aktuellen Position j
          delay(speedDelay);// wartet eine Zeitspanne, die durch speedDelay definiert ist, bevor die nächste Bewegung ausgeführt wird
          Serial.print("Servo 1 Position: ");// gibt die neue Position des Servos auf dem seriellen Monitor aus
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }
      if (servo01SP[i] < servo01SP[i + 1]) {//überprüft, ob die aktuelle Position kleiner ist als die nächste Position-> trifft dies zu, muss der Servo seine Position schrittweise erhöhen
        for ( int j = servo01SP[i]; j <= servo01SP[i + 1]; j++) {//startet Schleife, die Servo von seiner aktuellen Position bis zur Zielposition in Einzelschritten bewegt, j++ erhöht die Position in jedem Schritt um 1
          servo01.write(j);// bewegt Servo zu der aktuellen Position j
          delay(speedDelay);// wartet eine Zeitspanne, die durch speedDelay definiert ist, bevor die nächste Bewegung ausgeführt wird
          Serial.print("Servo 1 Position: ");// gibt die neue Position des Servos auf dem seriellen Monitor aus
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
            }
      }
// Code für die anderen Servos funktioniert genauso wie für Servo1, allerdings variieren die Variablen
      // Servo 2
      if (servo02SP[i] == servo02SP[i + 1]) {
        Serial.println("Servo 2 Position: Kein Wechsel"); // Nachricht über keinen Positionswechsel optional
      }
      if (servo02SP[i] > servo02SP[i + 1]) {
        for ( int j = servo02SP[i]; j >= servo02SP[i + 1]; j--) {
          servo02.write(j);
          delay(speedDelay);
          Serial.print("Servo 2 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }
      if (servo02SP[i] < servo02SP[i + 1]) {
        for ( int j = servo02SP[i]; j <= servo02SP[i + 1]; j++) {
          servo02.write(j);
          delay(speedDelay);
          Serial.print("Servo 2 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }

      // Servo 3
      if (servo03SP[i] == servo03SP[i + 1]) {
        Serial.println("Servo 3 Position: Kein Wechsel");// Nachricht über keinen Positionswechsel optional
      }
      if (servo03SP[i] > servo03SP[i + 1]) {
        for ( int j = servo03SP[i]; j >= servo03SP[i + 1]; j--) {
          servo03.write(j);
          delay(speedDelay);
          Serial.print("Servo 3 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }
      if (servo03SP[i] < servo03SP[i + 1]) {
        for ( int j = servo03SP[i]; j <= servo03SP[i + 1]; j++) {
          servo03.write(j);
          delay(speedDelay);
          Serial.print("Servo 3 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }

      // Servo 4
      if (servo04SP[i] == servo04SP[i + 1]) {
        Serial.println("Servo 4 Position: Kein Wechsel"); // Nachricht über keinen Positionswechsel optional
      }
      if (servo04SP[i] > servo04SP[i + 1]) {
        for ( int j = servo04SP[i]; j >= servo04SP[i + 1]; j--) {
          servo04.write(j);
          delay(speedDelay);
        }
      }
      if (servo04SP[i] < servo04SP[i + 1]) {
        for ( int j = servo04SP[i]; j <= servo04SP[i + 1]; j++) {
          servo04.write(j);
          delay(speedDelay);
          Serial.print("Servo 4 Position: ");
          Serial.println(j);// automatischer Zeilenumbruch wichtig für richtiges Lesen
        }
      }

      // Servo 5
      if (servo05SP[i] == servo05SP[i + 1]) {
        Serial.println("Servo 5 Position: Kein Wechsel");
      }
      if (servo05SP[i] > servo05SP[i + 1]) {
        for ( int j = servo05SP[i]; j >= servo05SP[i + 1]; j--) {
          servo05.write(j);
          delay(speedDelay);
          Serial.print("Servo 5 Position: ");
          Serial.println(j);
        }
      }
      if (servo05SP[i] < servo05SP[i + 1]) {
        for ( int j = servo05SP[i]; j <= servo05SP[i + 1]; j++) {
          servo05.write(j);
          delay(speedDelay);
          Serial.print("Servo 5 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }

      // Servo 6
      if (servo06SP[i] == servo06SP[i + 1]) {
        Serial.println("Servo 6 Position: Kein Wechsel"); // Nachricht über keinen Positionswechsel optional
      }
      if (servo06SP[i] > servo06SP[i + 1]) {
        for ( int j = servo06SP[i]; j >= servo06SP[i + 1]; j--) {
          servo06.write(j);
          delay(speedDelay);
          Serial.print("Servo 6 Position: ");
          Serial.println(j);
        }
      }
      if (servo06SP[i] < servo06SP[i + 1]) {
        for ( int j = servo06SP[i]; j <= servo06SP[i + 1]; j++) {
          servo06.write(j);
          delay(speedDelay);
          Serial.print("Servo 6 Position: ");
          Serial.println(j);
        }
      }
    }
  }
}



This is the app


this is the code for the app

The servos are powered with 4.24 V directly via the breadboard an not through the elegoo board. The servos drw over 1 ampere. Oh I almost forgot-apologies for the source code.

Thank you very much for your effort!

(Canned Reply: ABG- Export & Upload .aia)
Export your .aia file and upload it here.

export_and_upload_aia

.(We need to see Slider limits)

Regarding your blocks,

I see you are using Slider PositionChanged events to send commands, and I do not see any terminator character like '\n' in the text JOIN building each message.

(I can't see from here if you set the BlueTooth component to add that.)

The PosiitionChanged event fires rapidly while the thumb moves. This might overwhelm the Bluetooth data stream. A single fast Clock Timer that loops through the Sliders and sends updated values for the one whose thumb does not match a paired global variable would slow down the data traffic. You would need a number of global variables, to match the sliders.

If you add a message delimiter like \n to mark the end of each message, you would need to use a sketch command like readuntil(\n) (look it up in your language docs) to retrieve one complete command at a time from the BlueTooth data stream.

The board markup for code is ``` at start of line.
I editted your code for that.

That may have to do with the mechanical side of your Project. A video of the area(s) of concern could help us to understand more. Concerning "buzzing getting warm" - sounds like they are powered all of the time, whether or not they are moving. If that is a necessity, introduce some cooling - is the environment hot? Is the microprocessor board getting hot? That may need a heat sink or fan (or both).

Roboter_Arm_.aia (24.3 KB)

2codearbeit_zurVerwendung.ino (17.5 KB)

the first is for the MIT app inventor, the second is for the arduino ide

This old thread covers your problem.
Read it all the way through.

Unfortunately FireFox and Opera say:
"This video cannot be rendered because your browser does not support the codec."

...but my desktop players do.

What I was hoping for was detail - a detailed look at the physical areas of concern. At least the arm responds to a signal. There are a lot of joints in your cables and these could be causing some resistance, but that's the only detail revealed by your video that might contribute to overheating.

Concerning the jitters and twitching, it's possible that the arm joints are too loose and/or there is some resistance to their movement. It's also possible that your servo motors are not powerful enough (that would cause heat) or not fed the power they require.

sg90_datasheet.pdf (138.0 KB)

What material is the Arm made of?

The arm is made of PETG. I will try to send you some videos with the details but these will be very short because of the upload limit

Ive read trough this and will try to implent it. However, Im still not sure if I´ve understood the principle correctly. If someone has the time and could possibly correct it in my code-espacially the Arduino code-I would be very very grateful. Ill give it a try and send it here. But it might end up being quite embarassing for me if Ive done it completely wrong.


Is this correct in principle? For example, is it okay that I´m using dataIn, or am I heading completly in the wrong direction? And how should it look otherwise?
Thank you for your help

#include <SoftwareSerial.h>//importiert die SoftwareSerial-Bibliothek, um serielle Kommunikation auf anderen Pins als den Standortpins durchzuführen
#include <Servo.h>// importiert die Servo-Bibliothek, die für die Steuerung von Servomotoren genutzt werden

Servo servo01;
Servo servo02;
Servo servo03;
Servo servo04;
Servo servo05;
Servo servo06;// jede Zeile definiert ein Servo-Objekt, das zum Steuern eines Servomotors verwendet wird

SoftwareSerial Bluetooth(13 , 12); // erstellt eine SoftwareSerial-Verbindung auf den Pins 13(TX) und 12 (RX), um mit den HC-05-Bluetooth-Modul zu kommunizieren
int servo1Pos, servo2Pos, servo3Pos, servo4Pos, servo5Pos, servo6Pos; // speichert die aktuelle Position jedes Servos
int servo1PPos, servo2PPos, servo3PPos, servo4PPos, servo5PPos, servo6PPos; // previous position
int servo01SP[50], servo02SP[50], servo03SP[50], servo04SP[50], servo05SP[50], servo06SP[50]; // Array für jeden Servo, um bis zu 50 Positionen zu speichern
int speedDelay = 20;// Geschwindigkeit der Servo-Bewegung (Verzögerung zwischen den Bewegungen)
int index = 0;// Variable für den Index der gespeicherten Positionen im Array
String dataIn = "";// Variable zum Speichern von Daten, die über Bluetooth empfangen werden
void setup() {// diese Funktion wird nur einmal ausgeführt

Serial.begin(9600);// initialisiert die serielle Kommunikation mit einer Baudrate von 9600

  
  servo01.attach(5);// verbindet jeden Servo mit einem bestimmten Pin am Elegoo
  servo02.attach(6);
  servo03.attach(7);
  servo04.attach(8);
  servo05.attach(9);
  servo06.attach(10);
  Bluetooth.begin(9600); // initialisiert die Bluetooth-Kommunikation mit einer Baudrate von 9600
  Bluetooth.setTimeout(1);// setzt ein Timeout von 1ms für die Bluetooth-Kommunikation
  delay(20);// wartet 20ms, um die initiale Verbindung zu stabilisieren
  
  servo1PPos = 90;//setzt die Anfangsposition jedes Servos auf 90°
  servo01.write(servo1PPos);
  servo2PPos = 90;
  servo02.write(servo2PPos);
  servo3PPos = 90;
  servo03.write(servo3PPos);
  servo4PPos = 90;
  servo04.write(servo4PPos);
  servo5PPos = 90;
  servo05.write(servo5PPos);
  servo6PPos = 90;
  servo06.write(servo6PPos);
  Serial.println("init ok");
}

void loop() {// diese Funktion läuft kontinuierlich
  // put your main code here, to run repeatedly:
  // Check for incoming data
  if (Serial.available() > 0){
  dataIn = Serial.readStringUntil( '\n') ;
  Serial.print(state + "\n")

  if (Bluetooth.available() > 0) {// prüft, ob Daten vom Bluetooth-Modul empfangen wurden. Bluetooth.available()gibt die Anzahl der empfangenden Zeichen zurück
    dataIn = Bluetooth.readString();  // liest Daten als String und speichert sie in der Variablen data.In
    Serial.println("bluetooth ok");// gibt "Bluetooth ok" auf dem seriellen Monitor aus, um anzuzeigen, dass Daten erfolgreich empfangen wurden
    Serial.println(dataIn);//gibt die empfangenen Daten (dataIn) aus. printIn sorgt dafür, dass die Ausgabe in einer neuen Zeile endet

    // If "Waist" slider has changed value - Move Servo 1 to position
    if (dataIn.startsWith("s1")) {// prüft, ob der empfangene  Befehl (dataIn) mit "s1" beginnt. Dies weist darauf hin, dass es sich um einen Befehl für Servo1 handelt
      String dataInS = dataIn.substring(2, dataIn.length()); // extrahiert die Zahl(die Zielpositions des Servos) aus dem String
      servo1Pos = dataInS.toInt();  // konvertiert den extrahierten String in einen Ganzzahlwert und speichert ihn in der Variablen servo01Pos
      Serial.print("Servo 1: ");// gibt "Servo1" auf dem seriellen Monitor aus, um anzuzeigen, dass ein Befehl für Servo1 empfangen wurde 
      Serial.println(servo1Pos); // gibt die Zielposition von Servo1 auf dem seriellen Monitor aus
      
      // If previous position is bigger then current position
      if (servo1PPos > servo1Pos) {// prüft, ob die neue Zielposition (servo01Pos) größer ist als die aktuelle Position (servo01PPos).Wenn ja, bedeutet dies, dass sich der Servo nach vorne bewegen muss
        for ( int j = servo1PPos; j >= servo1Pos; j--) {   // Schleife, die den Servo Schritt für Schritt von der aktuellen Position (servo01PPos) zur Zielposition(servo01Pos) bewegt
          servo01.write(j);// sendet Winkel j an den Servo. Der Servo wird auf die entsprechende Position bewegt
          delay(20);    // wartet 20ms zwischen den Schritten. Dadurch wird die Bewegung des Servos langsamer und kontrollierter
        }
      }
      // If previous position is smaller then current position
      if (servo1PPos < servo1Pos) {// wenn die Zielposition(servo01Pos) kleiner ist als die aktuelle Position (servo01PPos), bewegt sich der Servo rückwärts
        for ( int j = servo1PPos; j <= servo1Pos; j++) {   // Schleife bewegt den Servo schrittweise rückwärts von der aktuellen Position zur Zielposition
          servo01.write(j);// sendet Winkel j an den Servo. Der Servo bewegt sich entsprechend
          delay(20);
        }
      }
      servo1PPos = servo1Pos;   // aktualisiert die aktuelle Position des Servos (servo01Pos) und speichert sie als vorherige Position (servo01PPos). Dies stellt sicher, dass die zukünftige Bewegung von der richtigen Starposition ausgeht

    }
    // Der gleiche Prozess folgt für alle anderen Servos, allerdings mit anderen Variablen-> der Code funktioniert nach dem gleichen Muster
      // Move Servo 2
    if (dataIn.startsWith("s2")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo2Pos = dataInS.toInt();
      Serial.print("Servo 2: ");
      Serial.println(servo2Pos);
      if (servo2PPos > servo2Pos) {
        for ( int j = servo2PPos; j >= servo2Pos; j--) {
          servo02.write(j);
          delay(50);
        }
      }
      if (servo2PPos < servo2Pos) {
        for ( int j = servo2PPos; j <= servo2Pos; j++) {
          servo02.write(j);
          delay(50);
        }
      }
      servo2PPos = servo2Pos;
    }
      // Move Servo 3
    if (dataIn.startsWith("s3")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo3Pos = dataInS.toInt();
      Serial.print("Servo 3: ");
      Serial.println(servo3Pos);
      if (servo3PPos > servo3Pos) {
        for ( int j = servo3PPos; j >= servo3Pos; j--) {
          servo03.write(j);
          delay(30);
        }
      }
      if (servo3PPos < servo3Pos) {
        for ( int j = servo3PPos; j <= servo3Pos; j++) {
          servo03.write(j);
          delay(30);
        }
      }
      servo3PPos = servo3Pos;
    }
     // Move Servo 4
    if (dataIn.startsWith("s4")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo4Pos = dataInS.toInt();
      Serial.print("Servo 4: ");
      Serial.println(servo4Pos);
      if (servo4PPos > servo4Pos) {
        for ( int j = servo4PPos; j >= servo4Pos; j--) {
          servo04.write(j);
          delay(30);
        }
      }
      if (servo4PPos < servo4Pos) {
        for ( int j = servo4PPos; j <= servo4Pos; j++) {
          servo04.write(j);
          delay(30);
        }
      }
      servo4PPos = servo4Pos;
    }
    // Move Servo 5
    if (dataIn.startsWith("s5")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo5Pos = dataInS.toInt();
      Serial.print("Servo 5: ");
      Serial.println(servo5Pos);
      if (servo5PPos > servo5Pos) {
        for ( int j = servo5PPos; j >= servo5Pos; j--) {
          servo05.write(j);
          delay(30);
        }
      }
      if (servo5PPos < servo5Pos) {
        for ( int j = servo5PPos; j <= servo5Pos; j++) {
          servo05.write(j);
          delay(30);
        }
      }
       servo5PPos = servo5Pos;
    }
    // Move Servo 6
    if (dataIn.startsWith("s6")) {
      String dataInS = dataIn.substring(2, dataIn.length());
      servo6Pos = dataInS.toInt();
      Serial.print("Servo 6: ");
      Serial.println(servo6Pos);
      if (servo6PPos > servo6Pos) {
        for ( int j = servo6PPos; j >= servo6Pos; j--) {
          servo06.write(j);
          delay(30);
        }
      }
      if (servo6PPos < servo6Pos) {
        for ( int j = servo6PPos; j <= servo6Pos; j++) {
          servo06.write(j);
          delay(30);
        }
      }
      servo6PPos = servo6Pos; 
    }
     // If button "SAVE" is pressed
    if (dataIn.startsWith("SAVE")) {// prüft, ob der empfangene Befehl "SAVE"ist. Dies bedeutet, dass die aktuellen Servo-Positionen gespeichert werden sollen
      Serial.println("SAVE");//gibt "SAVE" auf dem seriellen Monitor aus, um zu bestätigen, dass der Befehl empfangen wurde
      servo01SP[index] = servo1PPos;  // speichert die aktuellen Positionen der Servos (servo01PPos bis servo06PPos) in den Arrays servo01SP,servo02SP, etc.. Der Index gibt an, an welcher Stelle die Positionen im Array gespeichert werden
      servo02SP[index] = servo2PPos;
      servo03SP[index] = servo3PPos;
      servo04SP[index] = servo4PPos;
      servo05SP[index] = servo5PPos;
      servo06SP[index] = servo6PPos;
      index++;                        // erhöht den Index, sodass die nächste gespeicherte Position in einem neuen Slot des Arrays landet
    }
    // If button "RUN" is pressed
    if (dataIn.startsWith("RUN")) {//prüft, ob der empfangende Befehl "Run" ist. Dieser Befehl weist das Programm an, die gespeicherten Schritte auszuführen
      Serial.println("RUN");//gibt "RUN" auf dem seriellen Monitor aus, um zu bestätigen, dass der Befehl empfangen wurde
      runservo();  // ruft die Funktion runServo() auf, die die gespeicherten Schritte abarbeitet
    }
    // If button "RESET" is pressed
    if ( dataIn == "RESET") {//prüft, ob der empfangende Befehl "RESET" ist. Dieser Befehl löscht alle gespeicherten Schritte
      Serial.println("RESET");// gibt "RESET" auf dem seriellen Monitor aus, um zu bestätigen, dass der Befehl empfangen wurde
      memset(servo01SP, 0, sizeof(servo01SP)); // setzt alle Werte in den Arrays servo01SP bis Servo06SP auf 0. Dadurch werden die gespeicherten Schritte gelöscht
      memset(servo02SP, 0, sizeof(servo02SP));
      memset(servo03SP, 0, sizeof(servo03SP));
      memset(servo04SP, 0, sizeof(servo04SP));
      memset(servo05SP, 0, sizeof(servo05SP));
      memset(servo06SP, 0, sizeof(servo06SP));
      index = 0;  // setzt den Index auf 0 zurück, sodass neue Schritte wieder ab der ersten Position im Array gespeichert werden
    }
  }
}
// Automatic mode custom function - run the saved steps
void runservo() {// definiert die Funktion, die die gespeicherten Schritte wiederholt ausführt, bis der "RESET"-Befehl empfangen wird
  while (dataIn != "RESET") {   // führt Schleife kontinuierlich aus, solange der "RESET"-Befehl niicht empfangen wird
    for (int i = 0; i <= index - 2; i++) {  // durchläuft alle gespeicherten Schritte
      if (Bluetooth.available() > 0) {      // prüft, ob neue Daten über Bluetooth empfangen wurden
        dataIn = Bluetooth.readString();// liest die empfangenen Daten
        if ( dataIn == "PAUSE") {           // prüft, ob der "PAUSE"-Befehl empfangen wurde. Wenn ja, pausiert die Ausführung
          while (dataIn != "RUN") {         // wartet, bis der "RUN"-Befehl empfangen wird, um die Ausführung fortzusetzen
            if (Bluetooth.available() > 0) {
              dataIn = Bluetooth.readString();
              if ( dataIn == "RESET") {   // wenn der "RESET"-Befehl während der Pause empfangen wird, bricht die Schleife ab  
                break;
              }
            }
          }
        }
        // If speed slider is changed
        if (dataIn.startsWith("ss")) {//überprüft, ob der empfangende String (dataIn) mit den Buchstaben "ss" beginnt 
          String dataInS = dataIn.substring(2, dataIn.length());//schneidet die Zeichenkette so zu, dass nur die Zahl nach dem ss übrig bleibt
          speedDelay = dataInS.toInt(); // wandelt String in eine Ganzzahl und speichert diesen Wert in speedDelay -> dieser Wert wird später genutzt, um die Geschwindigkeit für die Bewegung der Servos festzulegen
        }
      }
      // Servo 1
      if (servo01SP[i] == servo01SP[i + 1]) {//überprüft, ob die aktuelle Servo-Position (servo01SP[i]) gleich der nächsten Position (servo01SP[i + 1]) ist
        Serial.println("Servo 1 Position: Kein Wechsel"); // gibt eine Nachricht auf dem seriellen Monitor aus, um anzuzeigen, dass kein Positionswechsel stattfindet
        // Elegoo sendet jede Servoposition zeilenweise an seriellen Monitor-> jede Position ist klar und getrennt sichtbar
      }
      if (servo01SP[i] > servo01SP[i + 1]) {// überprüft, ob die aktuelle Position größer ist als die nächste Position -> trifft dies zu, muss der Servomotor seine Position schrittweise verringern
        for ( int j = servo01SP[i]; j >= servo01SP[i + 1]; j--) {//startet Schleife, die den Servo von seiner aktuellen Position bis zur Zielposition in Einzelschritten bewegt, j-- verringert die Position in jedem Schritt um 1
          servo01.write(j);// bewegt Servo zu der aktuellen Position j
          delay(speedDelay);// wartet eine Zeitspanne, die durch speedDelay definiert ist, bevor die nächste Bewegung ausgeführt wird
          Serial.print("Servo 1 Position: ");// gibt die neue Position des Servos auf dem seriellen Monitor aus
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }
      if (servo01SP[i] < servo01SP[i + 1]) {//überprüft, ob die aktuelle Position kleiner ist als die nächste Position-> trifft dies zu, muss der Servo seine Position schrittweise erhöhen
        for ( int j = servo01SP[i]; j <= servo01SP[i + 1]; j++) {//startet Schleife, die Servo von seiner aktuellen Position bis zur Zielposition in Einzelschritten bewegt, j++ erhöht die Position in jedem Schritt um 1
          servo01.write(j);// bewegt Servo zu der aktuellen Position j
          delay(speedDelay);// wartet eine Zeitspanne, die durch speedDelay definiert ist, bevor die nächste Bewegung ausgeführt wird
          Serial.print("Servo 1 Position: ");// gibt die neue Position des Servos auf dem seriellen Monitor aus
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
            }
      }
// Code für die anderen Servos funktioniert genauso wie für Servo1, allerdings variieren die Variablen
      // Servo 2
      if (servo02SP[i] == servo02SP[i + 1]) {
        Serial.println("Servo 2 Position: Kein Wechsel"); // Nachricht über keinen Positionswechsel optional
      }
      if (servo02SP[i] > servo02SP[i + 1]) {
        for ( int j = servo02SP[i]; j >= servo02SP[i + 1]; j--) {
          servo02.write(j);
          delay(speedDelay);
          Serial.print("Servo 2 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }
      if (servo02SP[i] < servo02SP[i + 1]) {
        for ( int j = servo02SP[i]; j <= servo02SP[i + 1]; j++) {
          servo02.write(j);
          delay(speedDelay);
          Serial.print("Servo 2 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }

      // Servo 3
      if (servo03SP[i] == servo03SP[i + 1]) {
        Serial.println("Servo 3 Position: Kein Wechsel");// Nachricht über keinen Positionswechsel optional
      }
      if (servo03SP[i] > servo03SP[i + 1]) {
        for ( int j = servo03SP[i]; j >= servo03SP[i + 1]; j--) {
          servo03.write(j);
          delay(speedDelay);
          Serial.print("Servo 3 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }
      if (servo03SP[i] < servo03SP[i + 1]) {
        for ( int j = servo03SP[i]; j <= servo03SP[i + 1]; j++) {
          servo03.write(j);
          delay(speedDelay);
          Serial.print("Servo 3 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }

      // Servo 4
      if (servo04SP[i] == servo04SP[i + 1]) {
        Serial.println("Servo 4 Position: Kein Wechsel"); // Nachricht über keinen Positionswechsel optional
      }
      if (servo04SP[i] > servo04SP[i + 1]) {
        for ( int j = servo04SP[i]; j >= servo04SP[i + 1]; j--) {
          servo04.write(j);
          delay(speedDelay);
        }
      }
      if (servo04SP[i] < servo04SP[i + 1]) {
        for ( int j = servo04SP[i]; j <= servo04SP[i + 1]; j++) {
          servo04.write(j);
          delay(speedDelay);
          Serial.print("Servo 4 Position: ");
          Serial.println(j);// automatischer Zeilenumbruch wichtig für richtiges Lesen
        }
      }

      // Servo 5
      if (servo05SP[i] == servo05SP[i + 1]) {
        Serial.println("Servo 5 Position: Kein Wechsel");
      }
      if (servo05SP[i] > servo05SP[i + 1]) {
        for ( int j = servo05SP[i]; j >= servo05SP[i + 1]; j--) {
          servo05.write(j);
          delay(speedDelay);
          Serial.print("Servo 5 Position: ");
          Serial.println(j);
        }
      }
      if (servo05SP[i] < servo05SP[i + 1]) {
        for ( int j = servo05SP[i]; j <= servo05SP[i + 1]; j++) {
          servo05.write(j);
          delay(speedDelay);
          Serial.print("Servo 5 Position: ");
          Serial.println(j); // jede Position wird in eine neue Zeile geschrieben
        }
      }

      // Servo 6
      if (servo06SP[i] == servo06SP[i + 1]) {
        Serial.println("Servo 6 Position: Kein Wechsel"); // Nachricht über keinen Positionswechsel optional
      }
      if (servo06SP[i] > servo06SP[i + 1]) {
        for ( int j = servo06SP[i]; j >= servo06SP[i + 1]; j--) {
          servo06.write(j);
          delay(speedDelay);
          Serial.print("Servo 6 Position: ");
          Serial.println(j);
        }
      }
      if (servo06SP[i] < servo06SP[i + 1]) {
        for ( int j = servo06SP[i]; j <= servo06SP[i + 1]; j++) {
          servo06.write(j);
          delay(speedDelay);
          Serial.print("Servo 6 Position: ");
          Serial.println(j);
        }
      }
    }
  }
}

Must I correct something in the upper part as well?

Roboter_Arm__mitn.aia (24.5 KB)


This is the new MIT App inventor code. I hope it's approximately correct. Is something missing, or have I done something wrong? If so, I would be very grateful if you could help me with it

Roboter_Arm__mitn_value.aia (26.1 KB)
I've been experimenting with MIT App Inventor again and would like to share my updated code with you. However, there's one thing I'm stuck on. In the link you provided, there's an image showing something like when Screen1.Initialize followed by do set Slider 1....
But I don't seem to have those blocks. What should it look like in my case? Could someone show me?

09db8d399adf314888da99dd73b853ce14f6b9a1_2_690x221