6-Achsen Roboterarm mit ATMega328 und Servomotoren

This article was sent to us by our guest author Miguel Torres Gordo. Enjoy reading and building your own:

It has always fascinated me to see the movements of robotic arms when they do all kinds of work. Their movements are precise and continuous, as if I was in a dance class. These industrial robots have powerful motors and special electronic circuits to control movements according to programmed coordinates. Would it be possible to build a small robot arm with simple electronic modules and components?

The main problem is the weight of the structure of the robot arm and the actuators to move it. Ideally, the structure should be of metal and the actuators would have to be stepper motors, but this set is heavy and expensive. The question is: could it be done with servo motors?

We have to look for a material that is not very heavy and inexpensive. Balsa wood is used for inlays (marquetry), which is not heavy and yet resistant. So it is possible for servo motors to move the set, with the electronics for control already integrated there. We will develop a robot arm that picks up parts with a gripper and places them elsewhere.

The materials needed for this project are:

The required software is:

The first step is to design the structure of our robot arm from 3 mm thick balsa wood. In order for the different parts of our robot to be able to support the weight of the next part, we have to increase the thickness of these parts by gluing several equal pieces (the weight does not increase very much, as you will notice). To support the movements of the servo motors, we need to balance the weights of the arms a little, taking into account the weight of the arm at the other end.

Download drawings

For the operation of our robot arm it is very important to know the pulse width data of the servo motors in order to position the minimum and maximum angle with the adjustment sketches and to bring the robot arm into the desired position. According to the data sheet, the MG995 servo motor rotates 120 degrees, while the MG90S and SG90 servo motors rotate 180 degrees. To determine the required pulse width data, we use the Servo_check_120_degrees_slow_motion.ino and Servo_check_180_degrees.ino sketches and a protractor as shown in the drawing.

The two sketches are very similar, so we will explain the most important lines of one of the two sketches. The following lines belong to the MG995 servo motor sketch. The first two lines we analyse are the minimum and maximum values of the pulse width for each servo motor, corresponding to the positions 0 degrees and 180 degrees.

 #define SERVOMIN 100         // This is the 'minimum' pulse length count (out of 4096)
 #define SERVOMAX 500         // This is the 'maximum' pulse length count (out of 4096)

In the following lines we create two loops in which we have to change the data marked in red to position the servo motor between 30 degrees and 150 degrees. In this case we get the 120 degrees that the MG995 works with. The movement is slow with 10 "steps" every 50 milliseconds from 30 degrees to 150 degrees. We need to do these procedures with all the servo motors we will be using and write down the corresponding values for each one, as these are the values it works between to position itself.

for (int pos=165pos<430pos +=10) {       // Loop with movement slow from 30
  degrees to 150 degrees
  pwm.setPWM(00pos );
  Serial.println("165 pulse length count --> 30 degrees");
  delay(50);
}
delay (5000);

for (int pos_m=430pos_m>165pos_m -=10) {   // Loop with movement slow from 150
  degrees to 30 degrees
  pwm.setPWM(00pos_m );
  Serial.println("430 pulse length count --> 150 degrees");
  delay(50);
}
delay (5000);

Mounting

Once we have the minimum and maximum pulse values for the minimum and maximum working angle of each servo motor, it is time to assemble everything. To assemble properly, you can proceed as follows:

    1. we start mounting on the gripper with it closed and the servo motor turned 90 degrees.

    2. the next servo motor is number 1, with the position at 0 degrees and the gripper in the position shown in the photo, as the rotation is 180 degrees clockwise.

    3. the third servo motor is number 2, which, like the previous one, is in the 0 degree position and moves the grab vertically upwards as it also rotates clockwise to move in the direction of 180 degrees.

    4. now it is the turn of servo motor number 3, we leave the position of the servo motor at 90 degrees in this case and we mount the arm in alignment with the next one, as this gives us 60 degrees of movement in each direction.

    5. for servo motor number 4 we leave the position at 90 degrees and mount the arm horizontally (parallel to the ground), which gives us a large radius of action with 60 degrees in each direction, as with the previous servo motor.

    6. we leave the last servo motor, number 5, at 90 degrees like the previous one and mount the rotating platform so that the rest of the arm is in the middle of the side edge of the base.

    Circuit and description of operation

    As you can see in the circuit diagram, the circuit is very simple. We have the microcontroller, the PCA9685 module and the 6 servo motors.

    The electrical connections of the servo motors to the PCA9685 assembly are connected according to the numbering of the servo motor with the number of the corresponding PWM output port on the assembly, i.e. servo motor number 0 with output port 0.

    The 5V DC power supply is connected to the green screw connector on the driver board, paying attention to the polarity as the servo motors are supplied via this connector.

    The connections between the Atmega328P microcontroller and the PCA9685 module are the I2C communication via its port and the 5V for the power supply of the module electronics.

    The six servo motors are controlled by the Atmega328P microcontroller via the PCA9685 module, which has two important functions. The first is to supply the servo motors with 5V from an external power supply with enough power to move the 6 servo motors simultaneously. The second is to send the PWM signal to the respective servo motor, which was transmitted via the I2C signal from the microcontroller. As can be seen in the diagram above, we only need 2 pins for communication between the microcontroller and the PCA9685 module, leaving the other pins for other uses.

    The really tedious part of this project is setting the values for each position of the arm and the speeds of the movements. The latter must slow down if the arm is to pick up an object.

    For the adjustment and movement of the robot arm in each stage, one sketch per stage was created. This allows the settings to be made individually. When we have made all the settings correctly, we will combine them all into one sketch. We will use methods/functions so that the code is cleaner and easier to follow. Analyse the code for one stage and you will see that it is very simple. For the other stages, the adaptation method is similar.

    The code we will analyse is the settings for the robot arm to pick up the first part. The sketch is called pick_up_first_object.ino.

    The first two lines of code are the libraries we need for the sketch to run correctly. Wire.h is for I2C communication and Adafruit_PWMServoDriver is for using the PCA9685 module.

    #include <Wire.h>

    #include <Adafruit_PWMServoDriver.h>


    The next 4 lines are in order the implementation of an Adafruit_PWMServoDriver object to control the servo motor positions, SERVOMIN and SERVOMAX are the rising edge and falling edge values for the 0 degree and 180 degree position of the servo motors respectively. The speed variable is used for the waiting time until the next servo motor is moved.

    Adafruit_PWMServoDriver pca9685 = Adafruit_PWMServoDriver();


    #define SERVOMIN  100             

    #define SERVOMAX  500            


    int velocidad = 450;


    The next 4 lines are in order the implementation of an Adafruit_PWMServoDriver object to control the servo motor positions, SERVOMIN and SERVOMAX are the rising edge and falling edge values for the 0 degree and 180 degree position of the servo motors respectively. The speed variable is used for the waiting time until the next servo motor moves. In the setup() method we initialise the serial monitor and output a message. In the next two lines we initialise the PCA9685 module using its previously implemented object and specify the frequency at which the servo motors operate, 50 Hz.

    In the setup()-method we initialise the serial monitor and output a message. In the next two lines we initialise the PCA9685 module using its previously implemented object and specify the frequency at which the servo motors operate, 50 Hz.

    void setup() {

       Serial.println("Ajusting to Pick up first object");


       pca9685.begin();

       pca9685.setPWMFreq(50);


    }


    Now we implement the loop()-method. Here we start with the settings for each of the servo motors that need to act to execute the movement. We start with the first servo motor we want to move. Servo motor 5 is the one that rotates the robot arm. With the function pca9685.setPWM(5, 0, 350) we tell the PCA9685 module to move motor 5 to the position resulting from subtracting the value of the rising edge (0) from the falling edge (350), and with the function delay(velocidad ) we wait 450 milliseconds to execute the next function of the following servo motor.

    void loop() {

     

           // Servomotor 5

           pca9685.setPWM(5, 0, 350);

           delay(velocidad);


    The next two function calls execute the movements of servo motors 4 and 2. The execution is similar to the previous function, first move servo motor 4, wait 450 milliseconds and after this time move servo motor 2 to the position of the difference between the rising and falling edge.

           // Servomotor 4

           pca9685.setPWM(4, 0, 210);

           delay(velocidad);


           // Servomotor 2

           ca9685.setPWM(2, 0, 405);

           delay(velocidad);

    The following two functions execute the movements of servo motors 3 and 2. Let's explain why we have implemented loops for this. The movement of the previous servo motors is at the normal speed, which is very abrupt. To give the feeling of a slow speed, we have implemented a loop in which the servo motor moves one "step" every 10 milliseconds from the start position (150) of the variable pos to its end position (180) of the servo motor 3. The actual movement is intermittent, but because the waiting time between each movement is only 10 milliseconds, the movement gives a sense of continuity at low speed. As this makes the movement smooth, it helps us achieve good precision.

              // Servomotor 3

           for (int pos=150; pos<180; pos +=1) {

               pca9685.setPWM(3, 0, pos);

               delay(10);

           }


           // Servomotor 2

           for (int pos=405; pos>350; pos -=1) {

                 pca9685.setPWM(2, 0, pos);

                 delay(10);

           }


    The development of the last two functions that move servo motors 1 and 0 (gripper) is similar to that described above. Servo motor 1 moves at normal speed and servo motor 0, which is the gripper, closes it at slow speed because it is in a loop.

           // Servomotor 1

           pca9685.setPWM(1, 0, 300);

           delay(velocidad);


           // Servomotor 0

           for (int pos=200; pos>166; pos -=1) {

               pca9685.setPWM(0, 0, pos);

               delay(10);

           }

    The final waiting time in some of the individual sketches is 60 seconds, as these are movements within loops that are executed continuously. This way we can check which coordinates are correct in which positions and we can adjust the values of the variables pos of each servo motor so that the robot arm is positioned at the desired coordinates.

               delay(60000);

    }


    In order to make the adjustment at each stage, we need to run the corresponding sketch and vary the values of the pos variables of each servo motor until the robot arm reaches the desired position.

    The prepared sketch robot_arm.ino executes a path that starts from a safety position, moves two parts and returns to the safety position. I have tried to simplify the programming of this sketch as much as possible. Therefore, I have stored the code for respective stages as separate sketches and programmed them as functions in the loop() method of the robot_arm.ino sketch with the same names. This way we always know in which position our robot arm is.

    If the servomotors are connected to the PCA9685 module and this is supplied with voltage, the servos retain the position in which they are located. I exploited that to reduce the number of functions in some stages. If we have a servomotor in a position in the previous stage and the next one is the same, we do not need to change so that we eliminate the latter as it retains the position you had before.

    I hope you enjoy this project.

    Miguel Torres Gordo

    For arduinoProjects for beginners

    19 comments

    Sönke Friedrichs

    Sönke Friedrichs

    Die Zeichnungen am PC für die Roboterbauteile nehmen Form an ….
    Wenn diese fertig sind werde ich sie mit einem 3D- Drucker ausdrucken und die Ergebnisse über Herrn Wolter an Herrn Gordo weiterleiten.
    Dann sehen wir weiter, wie wir das mit den Dateien oder den Drucken machen ….

    WETTERENE

    WETTERENE

    https://www.thingiverse.com/thing:5198230

    WETTERENE

    WETTERENE

    merci pour le schéma, j’attend les moteurs et je mets les stl sur thingeverse

    Andreas Wolter

    Andreas Wolter

    Der Autor des Beitrags hat freundlicherweise in einer der PDFs die Maße des Greifers ergänzt. Die PDF-Datei wurde in der verlinkten ZIP-Datei ausgetauscht.

    Grüße,
    Andreas Wolter
    AZ-Delivery Blog

    Günter Keilhammer

    Günter Keilhammer

    @Sönke Friedrichs: hatte eine ähnliche Idee; falls möglich wäre super, wenn man die STL Files bekommen könnte?

    WETTERENE

    WETTERENE

    bonjour, serait-il possible d’avoir les mesures pour dessiner la pince
    svp
    je suis en train de dessiner les pièce avec Fusion 360
    ce projet est super

    Andreas Wolter

    Andreas Wolter

    um die Zeichnungen herunterzuladen, klicken Sie auf “Zeichnungen als Download”. Es sollte sich dann Google Drive öffnen und die Dateien in der ZIP aufgelistet werden. Sie können dann rechts oben auf den “Herunterladen”-Button klicken. Sier erhalten darüber alle PDFs als eine ZIP-Datei, die Sie auf Ihrem Rechner entpacken können.

    Die Videos werden zusätzlich bei Youtube hochladen. Dann sollte das Problem behoben sein. Es wird an dem Videocodec liegen, denke ich. Wenn dieser nicht installiert ist, kann man die Videos nicht abspielen.

    Was die ausverkauften Artikel angeht, können wir das leider nicht verhindern. Die Kollegen sind darum bemüht, den Bestand aufzufüllen. In einigen Fällen sind die Komponenten noch bei Amazon im AZ-Shop vorrätig. In diesem Fall jedoch nicht. Das tut uns leider.

    Wolfgang Menzel

    Wolfgang Menzel

    Hm, interessantes Projekt, wollte es eigenlich mit meinem Enkel realisieren. Leider sind die Motoren ausverkauft.
    Gruß

    Sönke Friedrichs

    Sönke Friedrichs

    @ Andreas Wolter, vielen Dank, habe die Zeichnungen gefunden !
    Ich zeichne die Bauteile gerade am PC.
    Zum Nachdrucken mit einem 3D- Drucker ….
    Vieleicht hat ja jemand Interesse daran ……
    Gerne würde ich hierzu auch mit Herrn Gordo in Kontakt treten :-)
    Ist das möglich ?? ( bin noch neu hier …… ;-) )

    Michael

    Michael

    Ich bekomme leider die Zeichnungsdateien nicht runter, kann sie auch nicht einsehen.

    mike

    mike

    videos gehen bei mir weder im firefox noch chromium unter LMDE 4/Linux

    Donboy

    Donboy

    Es gibt von mir sowas sehr ähnliches bereits zum 3D drucken unter : https://www.thingiverse.com/thing:597267 (siehe letztes Bild = Video) Der Trick ist es alle Servos gleichzeitig anzusteuern um somit anstatt jedem einzeln einen Winkel vorzugeben und abzuwarten, alle gleichzeitig zum Zielpunkt anlaufen zu lassen. Hier der relevante Code:

    #include
    #include
    Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

    #define SERVOMIN 240 // this is the ‘minimum’ pulse length count (out of 4096)
    #define SERVOMAX 470 // this is the ‘maximum’ pulse length count (out of 4096)

    uint8_t servonum = 7;
    int MOnPin = 7;
    int SOnPin = 8;
    int LOnPin = 1;
    boolean MOn = LOW;
    boolean SOn = LOW;
    float oS0;
    float oS1;
    float oS2;
    float oS3;
    float oS4;
    float oSC;

    void setup()
    {
    Serial.begin(9600);

    pinMode(SOnPin, OUTPUT); pinMode(MOnPin, OUTPUT); pinMode(LOnPin, OUTPUT); pwm.reset(); pwm.begin(); pwm.setPWMFreq(60); // Analog servos run at ~60 Hz updates digitalWrite(SOnPin, SOn); digitalWrite(MOnPin, MOn); InitArmPos(370, 500, 220, 200, 550, 700) ; ArmOn();

    }
    void loop() {
    // ( S0, S1, S2, S3, S4, SC, Stp, SetpDelay,Paus )
    MoveArm( 370, 500, 220, 200, 550, 700, 100, 2, 1000);
    MoveArm( 0 , 250, 470, 360, 0, 450, 100, 2, 1000);
    MoveArm( 200 , 0, 0, 200, 0, 450, 100, 2, 500);
    digitalWrite(LOnPin, HIGH);
    delay(500);
    MoveArm( 530, 0, 0, 0, 550, 0, 100, 2, 500);
    digitalWrite(LOnPin, LOW);
    MoveArm( 370, 0, 0, 0, 0, 0, 50, 1, 200);
    MoveArm( 0,500, 280, 220, 0, 650, 100, 2, 0);
    MoveTrack(80,80,500);
    MoveArm( 0, 430, 0, 360, 0, 550, 100, 2, 0);
    MoveTrack(-100,100,1000);
    MoveArm( 0, 0, 220, 440, 0, 450, 100, 2, 2000);
    MoveArm( 200, 0, 460, 200, 300, 0, 200, 5, 1000);
    MoveTrack(100,-100,1000);
    MoveArm( 530, 0, 0, 0, 0, 0, 50, 2, 1000);
    MoveArm( 200, 0, 0, 0, 0, 0, 50, 2, 500);
    MoveTrack(-80,-80,500);
    //delay(5000);
    }

    void TrackStop()
    {
    MoveTrack(0,0);
    }

    void ArmOn()
    {
    SOn= HIGH;
    digitalWrite(SOnPin, SOn);
    }

    void ArmOff()
    {
    SOn= LOW;
    digitalWrite(SOnPin, SOn);
    }

    void MoveTrack (int SL, int SR)
    {
    if ( SL !=0 || SR !=0)
    {
    MOn = HIGH;
    }
    else
    {
    MOn = LOW;
    }
    digitalWrite(MOnPin, MOn);
    pwm.setPWM(2, 0, 370 + SL);
    pwm.setPWM(1, 0, 370 – SR);
    }

    void MoveTrack (int SL, int SR, int pause)
    {
    MoveTrack (SL, SR);
    delay(pause);
    MoveTrack (0, 0);
    }

    void MoveArm(int nS0, int nS1, int nS2, int nS3, int nS4, int nSC, float duration, int delays, int pause)
    {
    float dS0 = (nS0 – oS0)/duration;
    float dS1 = (nS1 – oS1)/duration;
    float dS2 = (nS2 – oS2)/duration;

    float dS3 = (nS3 -oS3)/duration; float dS4 = (nS4 -oS4)/duration; float dSC = (nSC -oSC)/duration; for( int i=0 ; i<duration; i++) { if(nS0 > 0) { oS0 += dS0; pwm.setPWM(0, 0, oS0); } if (nS1 > 0) { oS1 += dS1; pwm.setPWM(4, 0, oS1); } if (nS2 > 0) { oS2 += dS2; pwm.setPWM(7, 0, oS2); } if (nS3 > 0) { oS3 += dS3; pwm.setPWM(3, 0, oS3); } if (nS4 > 0) { oS4 += dS4; pwm.setPWM(5, 0, oS4); } if (nSC > 0) { oSC += dSC; pwm.setPWM(6, 0, oSC); } Serial.print(oS0); Serial.print(“\t”); Serial.print(oS1); Serial.print(“\t”); Serial.print(oS2); Serial.print(“\t”); Serial.print(oS3); Serial.print(“\t”); Serial.print(oS4); Serial.print(“\t”); Serial.println(oSC); delay(delays); } delay(pause);

    }

    void InitArmPos(int nS0, int nS1, int nS2, int nS3, int nS4, int nSC)
    {
    digitalWrite(SOnPin, HIGH);
    delay(500);
    oS0 = nS0;
    oS1 = nS1;
    oS2 = nS2;
    oS3 = nS3;
    oS4 = nS4;
    oSC = nSC;
    pwm.setPWM(0, 0, oS0);
    pwm.setPWM(4, 0, oS1);
    pwm.setPWM(7, 0, oS2);
    pwm.setPWM(3, 0, oS3);
    pwm.setPWM(5, 0, oS4);
    pwm.setPWM(6, 0, oSC);
    delay(1000);
    digitalWrite(SOnPin, SOn);
    }
    Wer sich die Mühe macht, kann abhängig der Armlängen das ganze mathemathisch trigonometrisch in Relation stellen (Formeln) und dann als Zielkoordinaten (X,Y,Z) eingeben und der Arm positioniert sich ganu dort hin.

    Andreas Wolter

    Andreas Wolter

    @Sönke Friedrichs: die Zeichnungen sind als PDF Downloads verlinkt. Direkt unter der letzten Abbildung der Zeichnungen.

    Grüße,
    Andreas Wolter
    AZ-Delivery Blog

    Eugen Wirsing

    Eugen Wirsing

    Die Videos lassen sich herunterladen und mit z.B. VLC-Player abspielen.

    Sönke Friedrichs

    Sönke Friedrichs

    Ich bin 3D- Drucker …..
    Wenn mir jemand die Zeichnungen zukommen läßt …..
    Vieleicht sogar gleich als .stl …..
    Dann würde ich die Sperrholzteile drucken …..

    Andreas Wolter

    Andreas Wolter

    @Markus Pohle: ich habe es in Firefox unter Windows und Linux, sowie auf dem Smartphone getestet. Dort funktioniert es. Ich vermute, dass ein Videocodec fehlt, oder das Abspielen der Videos blockiert wird. Können Sie es auf anderen Geräten unter anderen Bedingungen nachvollziehen?

    Grüße,
    Andreas Wolter
    AZ-Delivery Blog

    Wolle

    Wolle

    Ein interessantes Projekt. Ich habe noch einen alten Plastik-Roboterarm. Vielleicht kann ich den nehmen und umrüsten.

    Markus Pohle

    Markus Pohle

    Schade, die Videos gehen nicht… ist das nur bei mir der Fall, da ich den Artikel über den Chrome Browser auf dem Handy schaue?

    Schill Gottfried

    Schill Gottfried

    einfach super
    danke für den Beitrag

    Leave a comment

    All comments are moderated before being published

    Recommended blog posts

    1. Install ESP32 now from the board manager
    2. Lüftersteuerung Raspberry Pi
    3. Arduino IDE - Programmieren für Einsteiger - Teil 1
    4. ESP32 - das Multitalent
    5. OTA - Over the Air - ESP programming via WLAN