Brazo robótico!
Autor: José Villagrán
El proyecto consiste en un brazo robótico con 4 servomotores a su disposición: uno en la base, que permitirá orientar al brazo de derecha a izquierda; uno en su brazo izquierdo, que subirá o bajará la altura de la garra; otro en su brazo derecho, que alejará o acercará la garra de frente; y, por último, un servomotor para abrir o cerrar la garra.
Cada servomotor está asignado a un eje de cada uno de los joysticks:
- Eje X del joystick izquierdo: mueve la base
- Eje Y del joystick izquierdo: mueve la parte de su derecha
- Eje X del joystick derecho: mueve la parte de su izquierda
- Eje Y del joystick derecho: abre o cierra el gripper
Además de haber logrado un movimiento sólido y fluido con cada uno de los servomotores, se añadió un sensor de luz en la garra, que detectará si un objeto está siendo colocado en medio de esta. Cuando esto ocurra y además se pulse el joystick izquierdo, el brazo se moverá de manera autónoma hacia el lado contrario, soltando el objeto y volviendo a la posición original.
Aquí se adjunta la memoria anexa:
Aquí un vídeo explicativo del proyecto:
Contenido multimedia:



Y el código arduino desarrollado:
#include <Servo.h>
/*
A1 = BASE
A0 = (ITS) RIGHT
6 = (ITS) LEFT
9 = CLAW
LEFT:
Y = A4 - S
X = A3 - S
B = 8 - S
v = 7 - v
G = 7 - G
RIGHT:
SW = 7 - S
VR_Y = A2 - S
VR_X = A5 - S
V = A2 - V
GND = A2 - G
*/
// Servos
Servo base, right, left, gripper;
// Pin Map
const uint8_t PIN_BASE = A1;
const uint8_t PIN_RIGHT = A0;
const uint8_t PIN_LEFT = 6;
const uint8_t PIN_GRIPPER = 9;
const uint8_t BTN_IZQ = 8;
const uint8_t PIN_SENSOR = 7;
const uint8_t JOY_LEFT_X = A3;
const uint8_t JOY_LEFT_Y = A4;
const uint8_t JOY_RIGHT_X = A2;
const uint8_t JOY_RIGHT_Y = A5;
// Angles constants
const int MIN_ANG = 5;
// Base constraints
const int MAX_BASE = 130;
const int MIN_BASE = 30;
// Right arm constraints
const int MIN_RIGHT = 75;
const int MAX_RIGHT = 150;
// Left arm constraints
const int MAX_LEFT = 120;
// Gripper constraints
const int MAX_GRIP = 50;
const int MIN_GRIP = 0;
const int ANG_VELOCITY = 1;
const int THRESHOLD = 100;
const int WAIT = 30;
const unsigned long COOLDOWN = 1500;
// Initial angles values
int baseAng = 80, rightAng = 150, leftAng = 80, gripperAng = 5;
// Manual mode, and when an object is detected
enum Mode { MANUAL, AUTO } mode = MANUAL;
unsigned long timeNext = 0;
unsigned long lastAuto = 0;
int cxL, cyL, cxR, cyR;
// Preparing the Serial, the servos, and the joystick centers
void setup() {
Serial.begin(9600);
base.attach(PIN_BASE);
right.attach(PIN_RIGHT);
left.attach(PIN_LEFT);
gripper.attach(PIN_GRIPPER);
applyAngles();
pinMode(PIN_SENSOR, INPUT);
pinMode(BTN_IZQ, INPUT_PULLUP);
delay(300);
cxL = analogRead(JOY_LEFT_X);
cyL = analogRead(JOY_LEFT_Y);
cxR = analogRead(JOY_RIGHT_X);
cyR = analogRead(JOY_RIGHT_Y);
Serial.println(cxL);
Serial.println(cyL);
Serial.println(cxR);
Serial.println(cyR);
delay(1000);
}
// Function to move the servos not that fast
void gotoSlow(Servo &s, int &varAng, int target, uint8_t pausa = 15) {
while (varAng != target) {
varAng += (varAng < target) ? ANG_VELOCITY : -ANG_VELOCITY;
s.write(varAng);
delay(pausa);
}
}
// Automatic "leave the piece" function
void autoSequence() {
int baseTargetAng;
if (baseAng < 90)
baseTargetAng = MAX_BASE;
else
baseTargetAng = MIN_BASE;
// Close gripper
gotoSlow(gripper, gripperAng, MIN_GRIP);
delay(15);
// Look at the right place
gotoSlow(right, rightAng, 120);
delay(15);
gotoSlow(left, leftAng, 100);
gotoSlow(base, baseAng, baseTargetAng);
delay(15);
delay(1500);
// Leave the piece, therefore open the gripper
gotoSlow(gripper, gripperAng, MAX_GRIP);
delay(15);
// Back to "home" position
gotoSlow(base, baseAng, 80);
// Close gripper again
gotoSlow(gripper, gripperAng, MIN_GRIP);
delay(15);
}
// Joysticks function, that uses the joystick centers of the beginning to know if they have been pushed
int pushJoy(int push, int center, int actualAng, bool inverse = false) {
int d = push - center;
if (abs(d) < THRESHOLD)
return actualAng;
int dir = (d > 0) ? +1 : -1;
if (inverse)
dir = -dir;
return actualAng + dir * ANG_VELOCITY;
}
// Function to move the servos to their actual angles
void applyAngles() {
base.write(baseAng);
right.write(rightAng);
left.write(leftAng);
gripper.write(gripperAng);
}
// Loop:
// If the mode is manual, it will read the joysticks and update each servo angle.
// After that, apllyAngles() will move the servos
// If the sensor is detecting something and the button of the left joystick is pressed, automatic mode is enabled
// --------------------------------------------------------------------------------------------------------------
// If the mode is automatic, then the autoSequence() will be called.
// Actions in loop will only be called if the actual time 'now' is greater than 'timeNext' (minicooldown)
// The automatic sequence will also have a cooldown of 1.5 secs
void loop() {
unsigned long now = millis();
if (mode == MANUAL) {
if (now >= timeNext) {
timeNext += WAIT;
baseAng = constrain(pushJoy(analogRead(JOY_LEFT_X), cxL, baseAng), MIN_BASE, MAX_BASE);
rightAng = constrain(pushJoy(analogRead(JOY_LEFT_Y), cyL, rightAng), MIN_RIGHT, MAX_RIGHT);
leftAng = constrain(pushJoy(analogRead(JOY_RIGHT_X), cxR, leftAng), MIN_ANG, MAX_LEFT);
gripperAng = constrain(pushJoy(analogRead(JOY_RIGHT_Y), cyR, gripperAng), MIN_GRIP, MAX_GRIP);
applyAngles();
}
bool sensorHit = digitalRead(PIN_SENSOR) == LOW;
bool btnHit = digitalRead(BTN_IZQ) == HIGH;
if (
sensorHit && btnHit && (now - lastAuto > COOLDOWN)) {
mode = AUTO;
Serial.print("ACTIVANDO MODO AUTOMATICO");
}
}
if (mode == AUTO) {
autoSequence();
lastAuto = millis();
mode = MANUAL;
}
}
Este proyecto ha despertado mi interés por el mundo de la electrónica y la visión del hardware aplicado al mundo real. La sensibilidad de los mecanismos reales hacen que problemas minúsculos acarreen una serie de problemas insoportables a futuro. Esto hace que un proyecto de este tipo sea, a mi parecer, completamente desafiante.
Aunque el diseño final no es el que pensé en un principio, he aprendido mucho y estoy orgulloso del resultado conseguido.