Robot pinza controlado remotamente para manipulación de precisión
Componentes y suministros
| Chasis Runt Rover Half-pint | × | 1 | |
![]() | Arduino UNO | × | 1 |
| Shield V5 | × | 1 | |
![]() | Cables jumper hembra-hembra | × | 1 |
| L9110S | × | 1 | |
| Soporte canal angular 90° (585424) | × | 1 | |
| Cubo de servo ligero, Futaba | × | 1 | |
| Kit pinza estándar A (637094) | × | 1 | |
| MG995 | × | 1 | |
| Placa de servo estándar | × | 1 | |
| Soporte canal angular 90° | × | 1 | |
| Portapilas 5 slots AA | × | 1 | |
| Pilas AA recargables | × | 5 | |
| Separadores nylon .750" 8-32 | × | 2 | |
| Tornillos .500" 6-32 con tuercas | × | 8 | |
| Tornillos .3125" 6-32 | × | 8 |
Aplicaciones y servicios en línea
![]() | Arduino IDE |
Acerca de este proyecto
Hace unos meses mi hijo me pidió un robot controlado por radio. Me dio una lista de deseos y la redujimos a algo manejable. Esto es lo que construí...
- Une el UNO y el shield V5 y encájalos.
- Coloca el conjunto UNO/Shield en el soporte central del robot.
- Usa cinta de doble cara: driver de motor en la pared izquierda, adaptador Bluetooth en la derecha.
Puedes fabricar tu propio chasis o elegir otro.
Paso 1: Software necesario
- Arduino IDE
- Python 2.7 (instalación completa con tkinter)
- Librería pySerial
- Librería controlador motor L9110S (archivo .zip adjunto)
- Código del robot (abajo o .zip adjunto)
- Aplicación Python de control remoto (archivos en este paso)
Paso 2: Lista de materiales hardware
- Chasis Runt Rover Half-pint o reemplazo 4WD cerrado adecuado
- Arduino Uno o similar con cable USB
- Shield sensor V5
- Driver motor L9110S (compra un par, son baratos)
- Servo MG995 o reemplazo adecuado x2
- Adaptador Bluetooth HC-05 o HC-06 x1
- Placa servo estándar B x1
- Soporte 90° x1
- Soporte simple x2
- Cubo servo ligero (525125 para Futaba) x1
- Kit pinza estándar A x1
- Cables jumper hembra-hembra
- 5 pilas AA recargables (NiMH) y cargador
- Cinta doble cara y bridas pequeñas
- Portapilas 5 slots AA (si usas AA recargables)
- Pack batería 6V NiMH o 7.4V Li-ion y cargador
- Tornillos 1.250" 6-32 x2
- Separadores nylon .750" 8-32 x2
- Tornillos .500" 6-32 con tuercas x8
- Tornillos .3125" 6-32 x8
Muchas piezas disponibles en eBay, Sparkfun, Adafruit, ServoCity.
Paso 3: Ensamblaje - Chasis
Ensambla el chasis siguiendo instrucciones incluidas o video. Al colocar la placa del controlador, usa los agujeros centrales para dejar espacio delante y detrás.
NOTA: Antes de continuar, quita las 4 ruedas para no dañar los motores al montar otros componentes.
Paso 4: Ensamblaje de la pinza
Ensambla la pinza siguiendo este video.
Paso 5: Montaje de la pinza - Paso 1
Necesitas: soporte 90°, cubo servo ligero, 4 tornillos .3125".
- Coloca el cubo en un lado del soporte y fija con tornillos .3125". Reserva.
- Pon tuercas en los dos tornillos cortos y aprieta.
- Toma los dos soportes simples, tornillos 1.250", 2 tornillos .500" con tuercas, 2 separadores nylon y placa servo B.
- Coloca un soporte simple dentro del Half-pint, pasa 2 tornillos 1.250" por agujeros izquierdos (desde dentro) y 2 tornillos .500" por derechos. Cabezas dentro.
- Coloca el segundo soporte simple en los tornillos por fuera.
- Pon separadores nylon en los tornillos largos (1.250") y atornilla la placa servo.
- Aprieta tornillos de la placa servo con llave hexagonal o destornillador.
Usa las fotos de referencia.






Paso 6: Montaje de la pinza - Paso 2
- Coloca el servo restante en el soporte con el eje arriba. Fija con 4 tornillos .3125".
- Monta la pinza en el soporte 90° con cubo servo usando 4 tornillos .500" con 2 tuercas 8-32 como separadores entre soporte y pinza. Asegura con otra tuerca encima.
- Coloca el conjunto pinza sobre el servo y usa tornillo de servo (del paquete) para fijar firmemente.
Pasa los dos cables de servo por el agujero del soporte plano al interior.





Paso 7: Montaje de electrónica
- Une UNO y shield V5.
- Coloca el conjunto en el soporte central.
- Cinta doble cara: driver motor en pared izquierda, Bluetooth en derecha.



Paso 8: Cableado - Motores
- A-1A (driver motor) → pin 5 (shield sensor)
- A-1B → pin 6
- B-1A → pin 3
- B-1B → pin 11
Con el frente del robot ALEJADO de ti:
- Lado IZQUIERDO: 2 cables NEGROS → primer terminal salida Motor A; 2 cables ROJOS → segundo terminal Motor A
- Lado DERECHO: 2 cables NEGROS → primer terminal salida Motor B; 2 cables ROJOS → segundo terminal Motor B
Servos:
- Cable servo Y → línea pin 2 (shield sensor). Cable blanco/naranja = señal.
- Cable servo X (pinza) → línea pin 7. Cable blanco/naranja = señal.
Paso 9: Cableado módulo Bluetooth
- Bluetooth Tx → pin 0 (shield sensor)
- Bluetooth Rx → pin 1
Paso 10: Alimentación
Conecta cables del portapilas 5 AA (u otro pack 6V) al terminal de alimentación del shield sensor:
- Rojo → Vcc
- Negro → GND
- Verifica que el jumper del shield V5 esté en su sitio.
- GND del L9110S → GND del shield sensor.
- Positivo de batería motores (6V o 7.2V) → Vcc del L9110S.
- Negativo (GND) batería motores → GND del shield motor.
Paso 11: Configurar módulo Bluetooth HC05/HC06
Entra en configuración Bluetooth del PC (Panel de Control / Sistema). Anota el nombre/puerto serie asignado.
- Windows
- Linux (uso blueman en Linux Mint, consulta tu distro)
- Mac
Paso 12: Cargar el código
Con cableado verificado, carga el código. Sigue instrucciones en web de Arduino para instalar IDE.
- Instala librería L9110 Motor Driver: descarga
L9110Driver.zip(PASO 1) y extrae en carpeta libraries de Arduino, o sigue instrucciones para añadir librería. - Carga código del robot en IDE desde
blue_t_slave.zip(PASO 1). - Conecta PC y Arduino por USB. En IDE: Herramientas → Placa → Uno. Herramientas → Puerto → tu COM. Sube.
Paso 13: Ejecutar aplicación Python de control
Descarga el zip de este paso, extrae en carpeta deseada. Abre terminal, navega a la carpeta y ejecuta: python rover.py. Debería abrirse una ventana como la imagen. Si hay errores (librerías faltantes), corrígelos.
Enciende el robot. Escribe el puerto COM del adaptador y pulsa "Conectar". Tras unos segundos, los controles se habilitan y el botón conectar se deshabilita: estás conectado. Si no conectas, usa Google.
La app permite control por ratón o teclado.
Controles teclado:
- Flechas: adelante, atrás, girar izquierda 90°, girar derecha 90°
- a: girar izquierda 45°
- s: girar derecha 45°
- h: alto (parar)
- y: establecer eje Y pinza
- u: abrir/cerrar pinza
- c: pinza home
Avance/retroceso son constantes (siguen hasta nueva orden o alto). Giros 90°/45° son temporales (paran tras retardo). Sliders pinza no ejecutan automáticamente: pulsa "Set" o tecla correspondiente. Valores 0-180.
- Eje Y pinza: 0 = todo arriba, 180 = todo abajo
- Abrir/cerrar pinza: 0 = cerrado, 180 = abierto
Botón "Desconectar" para salir: envía alto y home a pinza.

Código
GUI Driver Python Python
#!/usr/bin/env python
# Para Linux, BSD, Mac OSX: chmod +x para hacerlo ejecutable
###########
# App control Rover
# Escrito por Scott Beasley - 2015
# Libre para usar o modificar. Disfruta.
###########
import sys
import serial
import time
from Tkinter import *
import tkFont
import tkMessageBox
class App(Frame):
def createWidgets(self):
self.connected = False
self.message = StringVar()
helv6 = tkFont.Font(family='Helvetica', size=6, weight='normal')
self.frame = Frame(self.master)
self.frame.pack()
self.f1 = Frame(self.frame)
self.l1 = Label(self.f1, text="Puerto COM: ")
self.l1.pack(side=LEFT)
self.comm_entry = Entry(self.f1, bd=5, name="comm_entry")
self.comm_entry.pack(side=LEFT)
self.connectButton = Button(self.f1, text="Conectar", command=self.SerialConnect, name="b_connect")
self.connectButton.pack(side=LEFT)
self.disconnectButton = Button(self.f1, text="Desconectar", command=self.SerialDisconnect, name="b_disconnect")
self.disconnectButton.pack(side=RIGHT)
self.f1.grid(row=0, column=0)
self.f2 = LabelFrame(self.frame, bd=3, relief="groove", text="Control Terrestre")
self.g_vert_fm = Frame(self.f2)
self.grip_vert = Scale(self.g_vert_fm, from_=0, to=180)
self.grip_vert.grid(row=0, column=0, rowspan=4, sticky=W)
self.grip_vert_set = Button(self.g_vert_fm, text="Set", command=self.GripperY, name="b_grip_vert_set", width=1, height=2, font=helv6)
self.grip_vert_set.grid(row=5, column=0, sticky=W)
self.master.bind("<y>", self.GripperY)
self.g_vert_fm.grid(row=0, column=0, rowspan=4, sticky=W)
self.leftforwardButton = Button(self.f2, text="\\", command=self.TurnLeft45, name="b_left_forward")
self.leftforwardButton.grid(row=0, column=1)
self.master.bind("<a>", self.TurnLeft45)
self.leftButton = Button(self.f2, text="<", command=self.TurnLeft, name="b_left")
self.leftButton.grid(row=1, column=1)
self.master.bind("<Left>", self.TurnLeft)
self.rightforwardButton = Button(self.f2, text="/", command=self.TurnRight45, name="b_right_forward")
self.rightforwardButton.grid(row=0, column=3)
self.master.bind("<Right>", self.TurnRight45)
self.haltButton = Button(self.f2, text="¡Alto!", command=self.Halt, name="b_halt")
self.haltButton.grid(row=1, column=2)
self.master.bind("<h>", self.Halt)
self.rightButton = Button(self.f2, text=">", command=self.TurnRight, name="b_right")
self.rightButton.grid(row=1, column=3)
self.master.bind("<s>", self.TurnRight)
self.upButton = Button(self.f2, text="^", command=self.Forward, name="b_forward")
self.upButton.grid(row=0, column=2)
self.master.bind("<Up>", self.Forward)
self.leftdownButton = Button(self.f2, text="/", command=self.TurnRight45, name="b_left_down")
self.leftdownButton.grid(row=2, column=1)
self.downButton = Button(self.f2, text="V", command=self.Reverse, name="b_reverse")
self.downButton.grid(row=2, column=2)
self.master.bind("<Down>", self.Reverse)
self.f2.grid(row=1, column=0, pady=25)
self.rightdownButton = Button(self.f2, text="\\", command=self.TurnLeft45, name="b_right_down")
self.rightdownButton.grid(row=2, column=3)
self.g_horz_fm = Frame(self.f2)
self.grip_horz = Scale(self.g_horz_fm, from_=0, to=180, orient=HORIZONTAL)
self.grip_horz.grid(row=0, column=0, columnspan=7, sticky=E)
self.grip_horz_set = Button(self.g_horz_fm, text="Set", command=self.GripperX, name="b_grip_horz_set", width=1, height=2, font=helv6)
self.grip_horz_set.grid(row=0, column=8)
self.master.bind("<u>", self.GripperX)
self.g_horz_fm.grid(row=4, column=0, columnspan=7, sticky=E)
self.master.bind("<c>", self.GripperHome)
self.f3 = Frame(self.frame)
self.l2 = Label(self.f3, text="Última acción: ")
self.l2.pack(side=LEFT)
self.l3 = Label(self.f3, text=" ", textvariable=self.message)
self.l3.pack(side=RIGHT)
self.f3.grid(row=3, column=0, pady=8)
def CtrlButtonsState(self, bstate):
self.leftforwardButton.config(state=bstate)
self.leftButton.config(state=bstate)
self.rightforwardButton.config(state=bstate)
self.rightButton.config(state=bstate)
self.upButton.config(state=bstate)
self.leftdownButton.config(state=bstate)
self.downButton.config(state=bstate)
self.rightdownButton.config(state=bstate)
self.haltButton.config(state=bstate)
self.disconnectButton.config(state=bstate)
self.grip_horz.config(state=bstate)
self.grip_vert.config(state=bstate)
self.grip_horz_set.config(state=bstate)
self.grip_vert_set.config(state=bstate)
def ConnCtrlsState(self, bstate):
self.connectButton.config(state=bstate)
self.comm_entry.config(state=bstate)
def SerialConnect(self):
try:
self.ser = serial.Serial(self.comm_entry.get(), 9600)
except IOError:
tkMessageBox.showerror("Puerto COM inválido", "Puerto no encontrado.")
return
self.ConnCtrlsState(DISABLED)
self.CtrlButtonsState(NORMAL)
self.message.set("SerialConnect")
self.connected = True
time.sleep(3)
def SerialDisconnect(self):
try:
self.send_cmd('h', "¡Alto!")
time.sleep(1)
self.ser.close()
except IOError:
print "No se pudo cerrar puerto..."
self.message.set("SerialDisconnect")
self.ConnCtrlsState(NORMAL)
self.CtrlButtonsState(DISABLED)
self.connected = False
time.sleep(2)
def send_cmd(self, action, msg):
if self.connected:
for val in action:
self.ser.write(val)
self.ser.flush()
self.message.set(msg)
def TurnLeft(self, event=None):
self.send_cmd('a', "Izquierda")
def TurnLeft45(self, event=None):
self.send_cmd('q', "Izquierda45")
def TurnRight(self, event=None):
self.send_cmd('s', "Derecha")
def TurnRight45(self, event=None):
self.send_cmd('e', "Derecha45")
def Forward(self, event=None):
self.send_cmd('w', "Adelante")
def Reverse(self, event=None):
self.send_cmd('z', "Atrás")
def Halt(self, event=None):
self.send_cmd('h', "¡Alto!")
def GripperX(self, event=None):
grp_change = ('>', chr(self.grip_horz.get()), chr(255))
self.send_cmd(grp_change, "Pinza X")
def GripperY(self, event=None):
grp_change = ('^', chr(self.grip_vert.get()), chr(255))
self.send_cmd(grp_change, "Pinza Y")
def GripperHome(self, event=None):
self.send_cmd(('c', chr(255)), "Pinza Home")
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
self.CtrlButtonsState(DISABLED)
def main():
root = Tk()
root.geometry("450x350")
root.wm_title("Centro Control Rover (RCC)")
app = App(master=root)
app.mainloop()
if __name__ == '__main__':
main()
Código Rover Arduino
/* Bluetooth Rover. Objetivo: sigue tus comandos enviados mágicamente por el aire! O por USB :)
Escrito por Scott Beasley - 2015
Libre para usar o modificar. Disfruta. */
/* Usa librería L9110S. Funciona con puente H L9110S.
Descarga de https://github.com/jscottb/L9110Driver
o clona el zip de https://github.com (quita '-master' del nombre al añadir librería) */
#include <L9110Driver.h>
#include <Servo.h>
#define SERVO_Y 2 // Pin servo Y pinza
#define SERVO_CLAW 7 // Pin servo pinza
#define pinAIN1 5 // Interfaz I1
#define pinAIN2 6 // Interfaz I2
#define pinBIN1 3 // Interfaz I3
#define pinBIN2 11 // Interfaz I4
// Velocidades
#define MAXFORWARDSPEED 225
#define MAXBACKWARDSPEED 225
#define TOPSPEED 255 // Para girar mejor en alfombra/superficies rugosas
// Retardos
#define TURNDELAY 475
#define TURNDELAY45 235
#define BACKUPDELAY 400
#define SERVOMOVEDELAY 200
#define SERVOSEARCHDELAY 85
// Globales
L9110_Motor motor_left(pinAIN1, pinAIN2);
L9110_Motor motor_right(pinBIN1, pinBIN2);
Servo grip_y_servo;
Servo grip_servo;
void setup() {
Serial.begin(9600);
grip_y_servo.attach(SERVO_Y);
grip_y_servo.write(90);
grip_servo.attach(SERVO_CLAW);
grip_servo.write(90);
delay(500);
}
void loop() {
byte command = 0, val = 0;
if (Serial.available() > 0) {
command = Serial.read();
}
switch (command) {
case 'w': go_forward(); break;
case 'z': go_backward(); break;
case 'a': go_left(); delay(TURNDELAY); halt(); break;
case 's': go_right(); delay(TURNDELAY); halt(); break;
case 'q': go_left(); delay(TURNDELAY45); halt(); break;
case 'e': go_right(); delay(TURNDELAY45); halt(); break;
case 'h': halt(); break;
case '>':
val = Serial.read();
grip_servo.write(constrain(val, 64, 179));
break;
case '^':
val = Serial.read();
grip_y_servo.write(constrain(val, 53, 179));
break;
case 'c':
grip_y_servo.write(90);
grip_servo.write(90);
break;
case 255:
Serial.flush();
break;
}
Serial.flush();
delay(125);
}
void go_forward() {
ramp_it(MAXFORWARDSPEED, FORWARD, FORWARD);
motor_left.setSpeed(MAXFORWARDSPEED);
motor_right.setSpeed(MAXFORWARDSPEED);
motor_left.run(FORWARD|RELEASE);
motor_right.run(FORWARD|RELEASE);
}
void go_backward() {
ramp_it(MAXBACKWARDSPEED, BACKWARD, BACKWARD);
motor_left.setSpeed(MAXBACKWARDSPEED);
motor_right.setSpeed(MAXBACKWARDSPEED);
motor_left.run(BACKWARD|RELEASE);
motor_right.run(BACKWARD|RELEASE);
}
void go_left() {
ramp_it(TOPSPEED, BACKWARD, FORWARD);
motor_left.setSpeed(TOPSPEED);
motor_right.setSpeed(TOPSPEED);
motor_left.run(BACKWARD|RELEASE);
motor_right.run(FORWARD|RELEASE);
}
void go_right() {
ramp_it(TOPSPEED, FORWARD, BACKWARD);
motor_left.setSpeed(TOPSPEED);
motor_right.setSpeed(TOPSPEED);
motor_left.run(FORWARD|RELEASE);
motor_right.run(BACKWARD|RELEASE);
}
void halt() {
motor_left.setSpeed(0);
motor_right.setSpeed(0);
motor_left.run(BRAKE);
motor_right.run(BRAKE);
}
void ramp_it(uint8_t speed, uint8_t lf_dir, uint8_t rt_dir) {
uint8_t ramp_val = 0, step_val = 0;
step_val = abs(speed / 4);
if (!speed) step_val = -step_val;
for (uint8_t i = 0; i < 4; i++) {
ramp_val += step_val;
motor_left.setSpeed(ramp_val);
motor_right.setSpeed(ramp_val);
motor_left.run(lf_dir|RELEASE);
motor_right.run(rt_dir|RELEASE);
delay(25);
}
}
Driver L9110
Driver motor L9110 para Arduino: GitHub
Piezas personalizadas y cajas
4wdgripperbt2.fzz
Esquemáticos
4wdgripperbt2.fzz
Proceso de manufactura
- Sistema de Sensor de Temperatura Multiposición para Integración en Hogar Inteligente
- Controlador DIY para soldador 862D+ — Precisión y fiabilidad
- MotionSense: Detección inteligente de intrusos con Arduino y ESP8266
- Prevención de Incendios en Impresoras 3D: Sistema de Seguridad con Sensor Inteligente
- Levitación magnética repulsiva con Arduino: Circuito simple y guía DIY
- Registrador de Datos de Alto Rendimiento para Globo Meteorológico con Arduino
- ArduFarmBot Parte 2: Estación de Control IoT Remota para Cultivos
- Laboratorio avanzado de microcontroladores: ESP32, Arduino, PIC y módulos de sensores
- CoroFence: Detector Térmico Avanzado con Sensor PIR e Integración IoT
- Monitorización en la nube: Sistema de control remoto para gestión de activos en tiempo real
- 5 Beneficios clave del control remoto de producción para la industria moderna


