6-Achsen Roboterarm mit ATMega328 und Servomotoren

Esta publicación nos fue enviada por nuestro autor invitado Miguel Torres Gordo. Diviértase leyendo y en la construcción:

Siempre me ha fascinado ver los movimientos de los brazos robóticos cuando realizan todo tipo de tareas. Sus movimientos son precisos y continuos, como si estuviera en una clase de baile. Estos robots industriales disponen de potentes motores y circuitos electrónicos especiales para controlar los movimientos según las coordenadas programadas. ¿Sería posible construir un pequeño brazo robótico con módulos y componentes electrónicos sencillos?

El problema principal es el peso de la estructura del brazo robótico y los actuadores para moverlo. Lo ideal sería que la estructura fuera metálica y los actuadores tuvieran que ser motores paso a paso, pero este conjunto es pesado y caro. La pregunta es: ¿se podría hacer con servomotores?

Tenemos que buscar un material que no sea muy pesado y económico. Para la marquetería (trabajo de incrustación), se utiliza madera de balsa, que no es pesada y sí resistente. Así que es posible que los servomotores muevan el conjunto, con la electrónica para el control ya integrada allí. Desarrollaremos un brazo robótico que recoja piezas con una pinza y las coloque en otro lugar.

Los materiales requeridos para este proyecto son:

El software requerido es:

El primer paso es diseñar la estructura de nuestro brazo robótico con madera de balsa de 3 mm. Para que las diferentes partes de nuestro robot puedan soportar el peso de la siguiente parte, tenemos que aumentar el grosor de las mismas pegando varias piezas iguales (el peso no aumenta mucho como lo notarán). Para soportar los movimientos de los servomotores, tenemos que equilibrar un poco los pesos de los brazos, teniendo en cuenta el peso del brazo del otro extremo.

Dibujos como descarga ZIP (haga clic en "Descargar" en la nueva ventana de la parte superior derecha).

Para el funcionamiento de nuestro brazo robótico es muy importante conocer los datos del ancho de pulso de los servomotores para posicionar el ángulo mínimo y máximo con los bocetos de ajuste y llevar el brazo robótico a la posición deseada. Según la hoja de datos, el servomotor MG995 gira por 120 grados, mientras que los servomotores MG90S y SG90 giran 180 grados. Para determinar los datos de la anchura de pulso necesasria, utilizamos los sketches Servo_check_120_degrees_slow_motion.ino y Servo_check_180_degrees.ino y un transportador como se muestra en la figura.

Los dos bocetos son muy similares, por lo que explicaremos las líneas más importantes de uno de los dos sketches. Las siguientes líneas pertenecen al sketch del servomotor MG995. Las dos primeras líneas que analizamos son los valores mínimo y máximo del ancho de pulso de cada servomotor, correspondientes a las posiciones de 0 grados y 180 grados.

 #define servomine 100 // Este es el recuento de longitud de pulso 'mínimo' (de 4096)
 #define servomax 500 // Este es el recuento de longitud de pulso 'máximo' (de 4096)

En las siguientes líneas creamos dos bucles en los que tenemos que cambiar los datos marcados en rojo para posicionar el servomotor entre 30 grados y 150 grados. En este caso obtenemos los 120 grados con los que trabaja el MG995. El movimiento es lento, con 10 "pasos" cada 50 milisegundos, de 30 a 150 grados. Tenemos que hacer estos procedimientos con todos los servomotores que vayamos a utilizar y anotar los valores adecuados para cada uno de ellos, ya que son los valores entre los que trabajará para posicionarse.

por (En t pos=165; pos<430; pos +=10) {       // bucle con movimiento lento de 30
  grados a 150 grados
  Pwm.setpwm(0, 0, pos );
  De serie.Imprimir("Recuento de longitud de pulso 165 -> 30 grados");
  demora(50);
}
demora (5000);

por (En t Pos_m=430; Pos_m>165; Pos_m -=10) {   // bucle con movimiento lento de 150
  grados a 30 grados
  Pwm.setpwm(0, 0, Pos_m );
  De serie.Imprimir("430 cuenta de longitud de pulso -> 150 grados");
  demora(50);
}
demora (5000);

Montaje

Una vez que tenemos los valores de pulso mínimo y máximo para el ángulo de trabajo mínimo y máximo de cada servomotor, es el momento de ensamblar todo. Para realizar el ensamble correctamente, se puede proceder de la siguiente manera:

    1. Comenzamos el montaje en la pinza con ella cerrada y el servomotor girado 90 grados.

    2. El siguiente servomotor es el número 1, con la posición a 0 grados y la pinza en la posición que se muestra en la foto, ya que gira 180 grados en el sentido de las agujas del reloj.

    3. El tercer servomotor es el número 2, que, al igual que el anterior, está en la posición de 0 grados y mueve la pinza verticalmente hacia arriba, ya que también gira en el sentido de las agujas del reloj para moverse en la dirección de 180 grados.

    4. Ahora es el turno del servomotor número 3, en este caso dejamos la posición del servomotor a 90 grados y montamos el brazo en línea con el siguiente, ya que esto nos da 60 grados de movimiento en cada dirección.

    5. Para el servomotor número 4, dejamos la posición a 90 grados y montamos el brazo en horizontal (paralelo al suelo), lo que nos da un un gran radio de acción con 60 grados en cada dirección, como el servomotor anterior.

    6. Dejamos el último servomotor, el número 5, a 90 grados como el anterior y montamos la plataforma giratoria de forma que el resto del brazo quede en medio del borde lateral de la base.

    Circuito y descripción del funcionamiento

    Como puedes ver en el diagrama del circuito, éste es muy sencillo. Tenemos el microcontrolador, el módulo PCA9685 y los 6 servomotores.

    Las conexiones eléctricas de los servomotores a la placa PCA9685 se conectan según la numeración del servomotor con el número del puerto de salida PWM correspondiente en la placa, es decir, el servomotor número 0 con el puerto de salida 0.

    La fuente de alimentación de 5V DC se conecta al conector de tornillo verde de la placa del driver, prestando atención a la polaridad, ya que los servomotores se alimentan a través de este conector.

    Las conexiones entre el microcontrolador ATmega328P y el módulo PCA9685 son la comunicación I2C a través de su puerto y los 5V para la fuente de alimentación de la electrónica del módulo.

    Los seis servomotores son controlados por el microcontrolador ATmega328P a través del módulo PCA9685, que tiene dos funciones importantes. La primera es alimentar los servomotores con 5V desde una fuente de alimentación externa con suficiente potencia para mover las 6 servomotores al mismo tiempo. La segunda es enviar la señal PWM al respectivo servomotor, que se transmitió a través de la señal I2C desde el microcontrolador. Como se puede ver en el diagrama anterior, sólo necesitamos 2 pines para la comunicación entre el microcontrolador y el módulo PCA9685, dejando los otros pines para otros usos.

    La parte verdaderamente tediosa de este proyecto es establecer los valores para cada posición del brazo y las velocidades de los movimientos. Este último necesita reducir la velocidad si el brazo va a recoger un objeto.

    Para el ajuste y el movimiento del brazo robótico en cada etapa, se creó un boceto por etapa. Esto permite realizar los ajustes de forma individual. Cuando hayamos realizado todos los ajutes correctamente, los combinaremos todos en un único boceto. Al hacerlo, utilizaremos métodos/funciones para que el código sea más limpio y más fácil de seguir. Analice el código de una etapa y verá que es muy sencillo. Para las demás etapas, el método de adaptación es similar.

    El código que analizaremos es la configuración para que el brazo robótico recoja la primera pieza. El sketch se llama pick_up_first_object.ino.

    Las dos primeras líneas de código son las bibliotecas que necesitamos para que el sketch se ejecute correctamente. Wire.h es para la comunicación I2C y Adafruit_PWMServoDriver es para usar el módulo PCA9685.

    #include <Cable.H>

    #include <Adafruit_pwmservodriver.H>


    Las siguientes 4 líneas en orden son la implementación de un objeto Adafruit_PWMServoDriver para controlar las posiciones de los servomotores, SERVOMIN y SERVOMAX son los valores de flanco ascendente y flanco descendente para la posición de 0 grados y 180 grados de los servomotores respectivamente. La variable de velocidad se utiliza para el tiempo de espera hasta que se mueve el siguiente servomotor.

    Adafruit_pwmservodriver PCA9685 = Adafruit_pwmservodriver();


    #define Servomine 100

    #define Servomax 500


    En t velocidad = 450;


    Las siguientes 4 líneas en orden son la implementación de un objeto Adafruit_PWMServoDriver para controlar las posiciones de los servomotores, SERVOMIN y SERVOMAX son los valores de flanco ascendente y flanco descendente para la posición de 0 grados y 180 grados de los servomotores respectivamente. La variable de velocidad se utiliza para el tiempo de espera hasta que se mueve el siguiente servomotor. En el método setup() inicializamos el monitor serie y emitimos un mensaje. 

    En el método setup() inicializamos el monitor serie y emitimos un mensaje. En las siguientes dos líneas, inicializamos el módulo PCA9685 utilizando su objeto previamente implementado y especificamos la frecuencia a la que funcionan los servomotores, 50 Hz.

    vacío configurar() {

       De serie.Imprimir("Ajusting para recoger el primer objeto");


       PCA9685.Comenzar();

       PCA9685.setpwmfreq(50);


    }


    Ahora implementamos el método loop() aquí comenzamos con la configuración de cada uno de los servomotores que deben actuar para ejecutar del movimiento. Comenzamos con el primer servomotor que queremos mover. El servomotor 5 es el que hace girar el brazo robótico. Con la función PCA9685.setPWM(5, 0, 350) le decimos al módulo PCA9685 que mueva el motor 5 a la posición resultante de restar el valor del flanco de subida (0) al flanco de bajada (350), y con la función delay(velocidad ) esperamos 450 milisegundos para ejecutar la siguiente función del siguiente servomotor.

    vacío círculo() {

     

           // servo motor 5

           PCA9685.setpwm(5, 0, 350);

           demora(velocidad);


    Las dos siguientes llamadas de función ejecutan los movimientos de los servomotores 4 y 2. La ejecución es similar a la función anterior, primero mueve el servomotor 4, espera 450 milisegundos y después de este tiempo mueve el servomotor 2 a la posición de la diferencia entre el flanco de subida y el de bajada.

           // servomotor 4

           PCA9685.setpwm(4, 0, 210);

           demora(velocidad);


           // servomotor 2

           Ca9685.setpwm(2, 0, 405);

           demora(velocidad);

    Las dos funciones siguientes ejecutan los movimientos de los servomotores 3 y 2. Vamos a explicar por qué hemos implementado la bucles para esto. El movimiento de los servomotores anteriores es la velocidad normal, que es muy brusca. Para dar la sensación de una velocidad lenta, hemos implementado un bucle en el que el servomotor se mueven un "paso" cada 10 milisegundos desde la posición inicial (150) de la variable pos hasta su posición final (180) del servomotor 3. El movimiento real es un movimiento intermitente, pero como el tiempo de espera entre cada movimiento es de sólo 10 milisegundos, el movimiento da una sensación de continuidad a baja velocidad. Como esto hace que el movimiento sea suave, nos ayuda a conseguir una buena precisión.

           // SERVO MOTOR 3

           por (En t pos=150; pos<180; pos +=1) {

               PCA9685.setpwm(3, 0, POS);

               demora(10);

           }


           // servomotor 2

           por (En t pos=405; pos>350; pos -=1) {

                 PCA9685.setpwm(2, 0, POS);

                 demora(10);

           }


    El desarrollo de las dos últimas funciones que mueven los servomotores 1 y 0 (pinzas) es similar al anterior. El servomotor 1 se mueve a velocidad normal y el servomotor 0, que representa la pinza, la cierra a velocidad lenta porque está en un bucle.

           // servo motor 1

           PCA9685.setpwm(1, 0, 300);

           demora(velocidad);


           // servomotor 0

           por (En t pos=200; pos>166; pos -=1) {

               PCA9685.setpwm(0, 0, POS);

               demora(10);

           }


    El tiempo de espera final en algunos de los bocetos individuales es de 60 segundos, ya que se trata de movimientos dentro de bucles que se ejecutan continuamente. De esta manera, podemos comprobar qué coordenadas son correctas en qué posiciones y podemos ajustar los valores de las variables pos de cada servomotor para que el brazo robótico se posicione en las coordenadas deseadas.

           demora(60000);

    }


    Para hacer la configuración en cada nivel, debemos ejecutar el sketch correspondiente y variar los valores de las variables pos de cada servomotor hasta que el brazo robótico alcance la posición deseada.

    El sketch preparado robot_arm.ino ejecuta una trayectoria partiendo de una posición de seguridad, moviendo dos piezas y volviendo a la posición de seguridad. He intentado simplificar al máximo la programación de este sketch. Por lo tanto, he almacenado el código para las respectivas etapas como sketches separados y los he programado como funciones en el método loop () del sketch  robot_arm.ino con los mismos nombres. De este modo, siempre sabremos en qué posici´øn se encuentra nuestro brazo robótico.

    Cuando los servomotores están conectados al módulo PCA9685 y éste recibe voltaje, los servos mantienen la posición en la que se encuentran. He aprovechado para reducir el número de funciones en algunas etapas. Si tenemos un servomotor en una posición en la etapa anterior y la siguiente es la misma, no necesitamos cambiar por lo que eliminemos esta última ya que mantiene la posición que tenía antes.

    Espero que se divierta con este proyecto.

    Miguel Torres Gordo

    Para arduinoProyectos para principiantes

    19 comentarios

    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

    Deja un comentario

    Todos los comentarios son moderados antes de ser publicados

    Artículos de blog

    1. Ahora instalamos el esp32 a través de la administración.
    2. Lüftersteuerung Raspberry Pi
    3. Arduino IDE - Programmieren für Einsteiger - Teil 1
    4. ESP32 - das Multitalent
    5. Transporte Aéreo - programación de ESP mediante redes locales inalámbricas