(Última actualización 21/7/2019)
¡Hola, humano! Hoy voy a explicar cómo se puede comunicar una placa Arduino y controlarla mediante OpenCV. Más concretamente, voy a reciclar el código de mi tutorial de detección de colores: cada vez que la cámara vea un objeto verde de un cierto tamaño, se encenderá el led 13 de la placa Arduino.
Para ello utilizaremos la librería pySerial para poder enviar comandos por serial con python a Arduino.
Y como siempre, pondremos un poco de música mientras trabajamos por supuesto.
¿Por qué utilizar Arduino para controlar actuadores?
Si planeamos construir un robot que deba realizar cálculos complejos (como es el caso de la visión por computador) Arduino se nos queda corta.
Por esa razón, es mejor delegar el grueso de nuestros cálculos a nuestro PC o a una SBC como puede ser Raspberry Pi u otras más potentes (Wandboard, Odroid, etc). Muchas de estas placas disponen de pines GPIO para controlar actuadores, pero mi experiencia me dice que en muchas ocasiones son difíciles de configurar. Sin embargo, Arduino nos permite controlar estos actuadores muy fácilmente, de forma que es una buena idea conectarla a nuestra SBC para que reciba instrucciones vía USB.
Acerca de Pyserial
pySerial es una librería que permite enviar comandos, strings e información por Serial. Utilizar esta librería es la forma más sencilla que tenemos para enviar los datos de OpenCV a la placa Arduino.
pySerial viene por defecto con la última versión de Python, pero si por alguna extraña razón no la tienes y estás en Linux (Ubuntu, Debian o una distribución con sistema de paquetes .deb), abre la Terminal y escribe:
sudo apt-get install python-serial
Tutorial
Necesitamos:
- Ordenador con OpenCV y Arduino IDE instalados
- Placa Arduino y Cable USB. Cualquier modelo de Arduino valdrá.
- Webcam configurada y funcional
Comenzamos escribiendo el código para Arduino. Es muy sencillo: si recibe ‘h’ por serial se enciende el pin 13, si no, se apaga. Puedes conectar un LED exterior al pin 13 si lo prefieres.
/* Interaccion entre Arduino y OpenCV Codigo para Arduino Por Glar3 */ #define LED 13 char lectura; //Variable para guardar la lectura del Serial void setup() { //Iniciamos el Serial: Serial.begin(9600); //Inicializamos el pin 13 pinMode(LED, OUTPUT); } void loop() { //Si recibimos algo por serial, lo guardamos if(Serial.available() >= 1) { lectura = Serial.read(); //-Si recibiste 'h' -> enciende LED //-Si recibiste otro caracter -> apaga el LED if(lectura == 'h') { digitalWrite(LED, HIGH); } else { digitalWrite(LED, LOW); } } }
El código de OpenCV, como ya he dicho, es una variación del que escribí en el tutorial de detección de colores. Buscará un objeto verde y si este tiene un cierto tamaño, se envía el carácter ‘h’ por Serial. Si no, se envía ‘n’.
Si quieres entender cómo funciona el código de detección de colores deberías leer el tutorial original.
#Codigo de interaccion entre Arduino y OpenCV #Por Glar3 import cv2 import numpy as np import serial #cargamos la libreria serial #Iniciamos la camara captura = cv2.VideoCapture(0) #Iniciamos la comunicacion serial ser = serial.Serial('/dev/ttyUSB0', 9600) while(1): #Capturamos una imagen y la convertimos de RGB -> HSV _, imagen = captura.read() hsv = cv2.cvtColor(imagen, cv2.COLOR_BGR2HSV) #Establecemos el rango de colores que vamos a detectar #En este caso de verde oscuro a verde-azulado claro verde_bajos = np.array([49,50,50], dtype=np.uint8) verde_altos = np.array([80, 255, 255], dtype=np.uint8) #Crear una mascara con solo los pixeles dentro del rango de verdes mask = cv2.inRange(hsv, verde_bajos, verde_altos) #Encontrar el area de los objetos que detecta la camara moments = cv2.moments(mask) area = moments['m00'] #Descomentar para ver el area por pantalla #print(area) #Si el objeto tiene un area determinada, escribimos 'h' #Si no, escribimos un caracter erroneo if(area > 2000000): ser.write(str('h').encode()) else: ser.write(str('n').encode()) #Mostramos la imagen original y #la mascara cv2.imshow('mask', mask) cv2.imshow('Camara', imagen) tecla = cv2.waitKey(5) & 0xFF if tecla == 27: break cv2.destroyAllWindows()
¡Recuerda cambiar la dirección ‘/dev/ttyUSB0’ de la línea 13 por la dirección de tu Arduino! Si estás en linux seguramente no tendrás que cambiarla, y si estás en Windows será ‘COM3’ o un nombre parecido.
Y esto es todo por hoy. Si has seguido todos los pasos debería encenderse el LED 13 de Arduino cada vez que la cámara detecta un objeto de color verde. Si no te funciona, revisa el código. También puedes dejarme tus dudas en los comentarios y te responderé en cuánto pueda.
Por otra parte, si te sirvió este tutorial y quieres estar al día de nuestras publicaciones, no dudes en seguirnos en nuestra página de Twitter o Facebook 😉
Hola buenas.
Estoy intentando iniciar el programa con Python 3.7 y me da el siguiente error:
raise TypeError(‘unicode strings are not supported, please encode to bytes: {!r}’.format(seq))
TypeError: unicode strings are not supported, please encode to bytes: ‘n’
Creo que esto ocurre a partir del Python 3. ¿Se os ocurre una solución?
¡Buenas! Parece que es un error común cuándo se intenta enviar un string por serial con Python 3. La solución está en este hilo:
https://stackoverflow.com/questions/35642855/python3-pyserial-typeerror-unicode-strings-are-not-supported-please-encode-to
Es tan fácil como añadir “str.encode” dentro del ser.write. Por ejemplo “ser.write(str.encode(‘h’))” en vez de “ser.write(‘h’)”
¡Un saludo!
Hola, tengo un proyecto que consiste en usar una cámara que lee objetos en movimiento a altas velocidades y un motor que mueve un objeto bastante pesado, también tengo que conectar algunos suiches. bueno … el problema es que no sé por dónde empezar, estaba leyendo sobre el arduino y varios platos pero no lo decido, pensé que aquí podría ayudarme a decidir, ¿qué arduino usaría? ¿Qué cámara utilizarías para leer un balón de fútbol que se lanza con gran fuerza, por ejemplo :)? ¿Y qué tipo de motor utilizarías para mover una bolsa de cemento grande?
Hola buenas tardes, mi nombre es felix y queria hacerte una pregunta a ver si puedes echarme una mano. He leido vuestros manuales sobre deteccion de colores y de hecho he escrito un codigo python para cada uno de ellos, ya que los encesito por separado. bien, tengo un dron Phantom 4, un portatil con opencv y un punto de acceso wifi, lel dron se conecta a la wifi y le pongo la direccion ip donde quiero mandar el streaming (la ip del portatil), al portatil le digo que escuche al dron y que me abra una ventana con la… Leer más »
¡Hola Félix! Lo que me pides es muy amplio y bastante complejo: hay muchas cosas que podrían estar fallando: desde fallo con la antena a errores de lectura con el código, y no tengo ni idea de dónde puede estar el problema con tan poca información…
Intenta hacer un poco de debug y separar el problema en varias partes. ¿El portátil llega a conectarse con el dron? ¿Puedes enviar y recibir mensajes simples, como un string? Si estas dos cosas funcionan, puede ser que no tengas bien configurada la webcam o opencv esté leyendo una fuente de vídeo incorrecta.
Hola funciona con la webcam de la lap?
Hola, no entiendo a qué te refieres con “lap”.
hola! en visual studio community 2017 cambiaría mucho el código? no funciona ni lo primero!!!
import cv2
import numpy as np
perdón en 2015 quería decir…
vale genial es que no veía el open cv… es decir que se me ha desinstalado todo y lo he retomado desde hace meses y no puedo abrir open cv …. antes sí que me funcionaba
¿Has conseguido reinstalarlo?
Para todos los que se les queda encendido el led, es por que ocupan establecer bien la comunicación serial, para ello se ocupa un tiempo de espera depués de declarar la comunicación establecida.
————————————-
import time
ser = serial.Serial(‘COM6’, baudrate = 9600, timeout = 1)
time.sleep(4) #Genera un delay de 4 segundos (Puede ser distinto el tiempo)
————————————-
Pongan eso en vez de lo que se tiene en el código original suministrado por esta página.
gracias por el tutorial, agradecimientos desde Colombia. Muy bien explicado
Aun que tendría una duda, ¿como se aria, para que el sistema de reconocimiento de colores detecte no una si no varias cámaras con varios LED´s?
¡Hola Jhon! Disculpa la tardanza. Debes inicializar cada cámara en el código de OpenCV de esta forma:
Y después dentro del bucle guardar cada frame por separado y analizarlo:
Finalmente, en vez de enviar sólo el carácter ‘h’ y ‘l’, puedes enviar los carácteres ‘1’, ‘2’, ‘3’, ‘4’… y que Arduino encienda un LED diferente según el número que le llegue.
¡Espero que esto te ayude!
hola glare estoy haciendo un brazo robot con servos que selecciona objetos verdes, pero cuando la camara detecta el verde hace la misma secuencia de movimientos una y otra vez, mientras mas tiempo se quede el objeto verde en la camara mas secuencias hace, lo que quisiera es q solo lo haga una sola secuencia cada vez q detecta verde ¿que puede estar mal?… gracias
Hola Joel. Sin ver el cóidgo y con una descripción tan amplia no puedo estar segura de cuál es el fallo, pero creo que se solucionaría creando una variable booleana que se ponga a true la primera vez que el brazo robótico ejecute la acción. Y que la acción sólo se ejecute si la variable está a false. Así conseguirías que la secuencia sólo se ejecute una vez al detectar un objeto verde.
antes que todo quisiera agradecer por el excelente trabajo.
luego de seguir el tutorial no consigo que el led de arduino se apague. al momento de iniciar el proyecto el led se enciende hasta que detengo el proyecto. y lo ultimo quisiera saber si en la linea 17 esta expresión _, debe de ser reemplazada por algo?
desde ya un caluroso saludo
Digamos que obtengo los centros de el objeto capturado como envío los valores x e y por el serial???
Muchas gracias por tu aporte eres genial!!!!!
¡Fácil! ser.write(x) y ser.write(y)
hola amigo, gracias pero hice un cambio en el fichero python (para que funcione correrlo en termina) 🙂 #Codigo de interaccion entre Arduino y OpenCV #Por Glar3 import cv2 import numpy as np import serial #cargamos la libreria serial #Iniciamos la camara captura = cv2.VideoCapture(0) #Iniciamos la comunicacion serial ser = serial.Serial(‘/dev/ttyACM0’, 9600) while(1): #Capturamos una imagen y la convertimos de RGB -> HSV _, imagen = captura.read() hsv = cv2.cvtColor(imagen, cv2.COLOR_BGR2HSV) #Establecemos el rango de colores que vamos a detectar #En este caso de verde oscuro a verde-azulado claro verde_bajos = np.array([49,50,50], dtype=np.uint8) verde_altos = np.array([80, 255, 255], dtype=np.uint8)… Leer más »
Disculpa no se como modificar lo anterior al parar el programa de Python se apaga Rx y Led permanente encendido. Al iniciarlo Led y Rx permanente encendidos. El Reset apaga el led. Y así no hay forma que funcione luego de presionar el Esc en la primera corrida luego de reconectar todo.
Permanece encendido porque al apagar python el LED no recibe la orden de apagarse, pero se apaga con RESET porque este botón reinicia el programa de la placa Arduino.
No sé cuál es la razón de que no funcione el programa de Python otra vez con Arduino. Si has desconectado la placa y la has vuelto a conectar puede ser que cambie de dirección Serial, de ahí el problema.
Hoy reconecte todo de nuevo a la pc y corri el código tal y como lo tienes solo cambiando “ser = serial.Serial(‘/dev/ttyUSB0’, 9600)” por “ser = serial.Serial(‘COM’, 9600)”. Todo funciona bien si pongo algo verde enciende si lo quito se apaga. Retiro el verde y presiono Esc y de nuevo mas nunca funciona. Al correrlo se enciende el led permanentemente así como Rx flashea permanentemente este el verde o no. Presiono Esc sale el programa de python y se queda el led encendido y Rx flasheando. Si presiono el Reset de la placa Arduino se apaga LED y Rx, pero… Leer más »
Oye amigo, quiero hacer el seguimiento de el color amarillo, ¿me podrias decir la escala HSV del amarillo?
Hola Daniel. Mírate el final de este tutorial, dónde pone “Actualización 12/11/2015”:
http://robologs.net/2014/07/02/deteccion-de-colores-con-opencv-y-python/
Allí explico cómo encontrar tu propio rango de colores.
Me funciono solo una vez. Estoy usando python-2.7.10.amd64, pyserial-2.7.win32, opencv 3.0, numpy-1.9.3+mkl-cp27-none-win_amd64, Arduino Mega 2560 copia china con chipset CH341SER-64BIT, LifeCam HD-3000, windows 7 ultimate 64 bit Sp1 Spanish. El primer código que va al Arduino *.ino solo me llama la atención que nunca se cierra la comunicación del puerto serial quizás no haga falta. Cambie la linea “ser = serial.Serial(‘/dev/ttyUSB0’, 9600)” por “ser = serial.Serial(‘COM’, 9600)” y funcionó. Pero sucede que en vez de cerrar con Esc como esta previsto lo detuve con Ctrl+C luego de esto mas nunca funcionó. Del código en python me llama la atención que… Leer más »
Pues por lo que me dices, ya te funciona bien. El LED Rx de Arduino se enciende porque OpenCV detecta un área de color verde y le envía el carácter ‘h’ a Arduino, o el carácter ‘n’ si el área es pequeña (Rx se enciende cuándo se recibe algo por Serial). Además es normal que el LED 13 se encienda, esto es precisamente lo que tiene que hacer el programa. Cuando cierras el programa, si el LED 13 está encendido ya no recibirá la orden de apagarse por Serial. Por esta razón se te queda encendido y sólo se para… Leer más »
Buenos días! Primero de todo, felicitaros a los administradores de esta página y a ti Glare en especial por este tutorial. He tenido un problema con el código, me salía un error diciendo que el programa de python no era capaz de encontrar el puerto. Cambié esta línea de código: ser = serial.Serial(‘/dev/ttyUSB0’, 9600) por esta otra: ser = serial.Serial(“COM3”). COM3 es el puerto por el que suelen conectar las placas de arduino. Con este cambio el programa me funciona perfectamente, dejo el comentario por si alguien mas tiene este problema que he tenido yo. Un saludo a todos y… Leer más »
Pues tienes razón, debería haber puesto que hay que cambiar esta línea por tu dirección Serial. ¡Gracias por la corrección!
como conecto la arduino con la rasberry
me podrías pasar un esquema
Esto… con un cable USB conectado de la Raspberry a Arduino
como descargo el arduino a las rasberry o donde pongo el codigo de arduino
El código de Arduino tienes que pasarlo a la placa Arduino por USB y después ejecutar el código de Python dentro de la Raspberry.
Buenas tardes!
Disculpa estoy empezando este campo de detección de colores y mi duda es como se le hace para determinar los altos y los bajos del color de las matrices.
¡Hola Jess!En la primera matriz tienen que aparecer los valores mínimos de H, S y V que quieres detectar, y en la segunda matriz los máximos.
Si dudas cuáles son los números, puedes abrir una paleta de colores HSV y mirarlo (por ejemplo http://www.rapidtables.com/web/color/RGB_Color.htm)
Muchas gracias GL4R3! voy a trabajar con detección de 2 dos colores para enviarle información a un motor para encenderlo o apagarlo.
Glare estoy haciendo un programa que haga una discriminacion de tres colores con arduino y le puse lo siguiente y los reconoce segun su rango
verde_bajos = np.array([49,50,50], dtype=np.uint8)
verde_altos = np.array([80, 255, 255], dtype=np.uint8)
amarillo_bajos = np.array([15,50,50], dtype=np.uint8)
amarillo_altos = np.array([40,255,255], dtype=np.uint8)
rojo_bajos = np.array([140,50,50], dtype=np.uint8)
rojo_altos = np.array([243, 255, 255], dtype=np.uint8)
me puedes explicar como es funciona estas matrices que significa cada numero si no es mucho pedir gracias
¡Buenos días, Joel!
Cada una de las matrices es el código de un color en RGB. Por ejemplo, el verde_altos es en este caso el [80,255,255], que en RGB se corresponde a un verde claro, casi azulado:
http://www.colorschemer.com/online.html
Lo mismo con los otros colores. Esto te sirve para establecer el rango de color: cualquier color entre verde_bajos y verde_altos será considerado verde. Lo mismo con los amarillos y los rojos.
gracias gl4re
Hola buenas, soy algo nuevo en esto de OpenCV pero poseo conocimientos de electrónica. Quiero saber si es posible que nos contactemos y me puedas ayudar en un proyecto que estoy realizando. Te lo agradecería un montón y obviamente si necesitas ayuda en electrónica y electricidad también puedo brindarla 🙂
Últimamente estoy bastante liada, pero si quieres escríbeme un mail e intentaré ayudarte o, por lo menos, te daré documentación. ^^
glare.676c617265@gmail.com
***ACTUALIZACIÓN 6/12/2014***
Después de hablarlo con los administradores, preferimos que planteéis vuestras dudas en los comentarios de cada tutorial. ¿Nos hemos vuelto antipáticos y humanófobos de repente? ¡No, hombre! Bueno, por lo menos no más que de costumbre… pero de esta forma cualquiera de nuestros lectores podrá aprender de las dudas y errores de los demás, y también podrá dar su opinión ^ ^
[…] Arduino y OpenCV con pySerial […]