Buenas tardes, queridos lectores de Habr! Este es el segundo artículo de una serie de artículos sobre el uso práctico de ROS en la Raspberry Pi. En el primer artículo de la serie, describí la instalación de los componentes ROS necesarios y la configuración del entorno de trabajo para el trabajo.En la segunda parte de la serie, comenzaremos a usar de manera práctica las funciones de ROS en la plataforma Raspberry Pi. Específicamente, en este artículo voy a hablar sobre el uso de la placa de cámara Raspberry Pi en la Raspberry Pi junto con ROS para resolver problemas de visión por computadora. ¿Quién está interesado, por favor, debajo del gato.Camera RPi Camera Board
Para el trabajo, necesitaremos una cámara de placa de
cámara Raspberry Pi: esta cámara se conecta directamente a la GPU a través de un conector CSi en la placa, que le permite grabar y codificar la imagen de la cámara sin usar el tiempo del procesador. Se utiliza un cable ZIF para conectar la cámara. El conector del cable en la placa se encuentra entre los puertos Ethernet y HDMI:
Instalación de biblioteca
Así que procedamos a instalar las bibliotecas necesarias. Primero, instale OpenCV:$ sudo apt-get install libopencv-dev
Para usar la cámara Raspberry Pi, necesitaremos la biblioteca raspicam. Descargue el archivo desde aquí .A continuación, instale la biblioteca:$ tar xvzf raspicamxx.tgz
$ cd raspicamxx
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install
$ sudo ldconfig
Debe habilitar el soporte de la cámara en Raspbian a través del programa raspi-config:$ sudo raspi-config
Seleccione la opción 5 - Activar cámara, guardar la selección y reiniciar el sistema.Comenzando con ROS
Para mayor comodidad, cree un nuevo taller de amentos para nuestros paquetes:$ mkdir -p ~/driverobot_ws/src
$ cd ~/driverobot_ws/src
$ catkin_init_workspace
$ cd ~/driverobot_ws
$ catkin_make
Cree un nuevo paquete ROS:$ cd src/
$ catkin_create_pkg raspi_cam_ros image_transport cv_bridge roscpp std_msgs sensor_msgs compressed_image_transport opencv2
La especificación del comando catkin_create_pkg es la siguiente: catkin_create_pkg <package_name> [depend1] [depend2],donde puede especificar cualquier dependencia de la biblioteca, las bibliotecas que utilizará el paquete.Este comando crea el marco del proyecto ROS: un directorio src vacío para scripts de nodo y archivos de configuración CMakeLists.txt y package.xml.Encontré un guión simple que recibe fotogramas de la cámara y los publica usando el "editor" (editor), y lo adapté para ROS Indigo. Puedes descargarlo desde aquí .Para usarlo, debe instalar el controlador de cámara Raspberry Pi UV4L:$ curl http://www.linux-projects.org/listing/uv4l_repo/lrkey.asc | sudo apt-key add -
Agregue la siguiente línea al archivo /etc/apt/sources.listdeb http://www.linux-projects.org/listing/uv4l_repo/raspbian/ wheezy main
Actualice los paquetes e instálelos:$ sudo apt-get update
$ sudo apt-get install uv4l uv4l-raspicam
Para descargar el controlador, en cada arranque del sistema, también instalamos un paquete opcional:$ sudo apt-get install uv4l-raspicam-extras
Pasemos a editar el paquete. Pegue las líneas desde aquí en su archivo CMakeLists.txt .Las líneas más importantes en el archivo CMakeLists.txt:link_directories(/usr/lib/uv4l/uv4lext/armv6l/)
…
target_link_libraries(capture ${catkin_LIBRARIES} uv4lext)
Por lo tanto, agregamos un enlace al controlador uv4l, que es necesario para compilar el paquete.Al final del archivo, establecemos líneas especiales para nuestro nodo:add_executable(capture src/capturer.cpp)
target_link_libraries(capture ${catkin_LIBRARIES} uv4lext)
La línea add_executable crea un binario para el lanzamiento y target_link_lbraries vincula bibliotecas adicionales para el binario de captura.Pegue las líneas que faltan desde aquí en el archivo package.xml para que se vea así:<?xml version="1.0"?>
<package>
<name>raspi_cam_ros</name>
<version>0.0.0</version>
<description>The raspi_cam_ros package</description>
<maintainer email="pi@todo.todo">pi</maintainer>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>cv_bridge</build_depend>
<build_depend>image_transport</build_depend>
<build_depend>roscpp</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>sensor_msgs</build_depend>
<build_depend>opencv2</build_depend>
<build_depend>compressed_image_transport</build_depend>
<run_depend>cv_bridge</run_depend>
<run_depend>image_transport</run_depend>
<run_depend>roscpp</run_depend>
<run_depend>std_msgs</run_depend>
<run_depend>sensor_msgs</run_depend>
<run_depend>opencv2</run_depend>
<run_depend>compressed_image_transport</run_depend>
</package>
Las primeras líneas establecen los parámetros básicos del nodo: nombre, versión, descripción, información sobre el autor. Las líneas build_depend determinan las dependencias de la biblioteca necesarias para compilar el paquete, y las líneas run_depend determinan las dependencias necesarias para ejecutar el código en el paquete.Cree un archivo capturer.cpp dentro de la carpeta src y pegue las líneas desde aquí . Aquí en el método main (), el nodo se inicializa y se inicia en un bucle:ros::init(argc, argv,"raspi_cam_ros");
ros::NodeHandle n;
UsbCamNode a(n);
a.spin();
Toda la lógica del guión es que obtenemos la imagen de la cámara usando OpenCV, la envolvemos en un mensaje para ROS en el método fillImage y la publicamos en el tema. Aquí el paquete image_transport se usa para crear una imagen de "editor".Inicie el controlador uv4l ejecutando el comando:$ uv4l --driver raspicam --auto-video_nr --width 640 --height 480 --nopreview
lo que creará la transmisión MJPEG.Compile nuestro nodo ROS:$ roscore
$ cd ~/driverobot_ws
$ catkin_make
Verifique el valor de la variable ROS_PACKAGE_PATH:echo $ROS_PACKAGE_PATH
/opt/ros/indigo/share:/opt/ros/indigo/stacks
El valor de la variable ROS_PACKAGE_PATH debe incluir la ruta a nuestro espacio de trabajo. Agregue nuestro espacio de taller a la ruta:$ source devel/setup.bash
Ahora ejecutando el comando echo $ ROS_PACKAGE_PATH nuevamente, deberíamos ver una salida similar:/home/youruser/catkin_ws/src:/opt/ros/indigo/share:/opt/ros/indigo/stacks
, donde / home / <user_name> / catkin_ws / src es la ruta a nuestro espacio de trabajo. Esto significa que ROS puede "ver" nuestros nodos creados en catkin_ws y podemos ejecutarlos a través de rosrun.Ejecute nuestro nodo ROS:$ rosrun raspi_cam_ros capture
Ejecute el programa gráfico rqt_image_view para mostrar la secuencia de video del tema:$ rosrun rqt_image_view rqt_image_view
Seleccione el tema image_raw en la ventana rqt_image_view.
Al iniciar el nodo, puede aparecer el error "Gtk-WARNING **: no se puede abrir display: -1" cuando se trabaja a través de ssh o "GdkGLExt-WARNING **: el sistema de Windows no es compatible con OpenGL". cuando se ejecuta en modo de escritorio remoto VNC. La solución es conectarse a Raspberry Pi a través de SSH con reenvío X11:$ ssh -X pi@<host_pi>
Puede averiguar con qué frecuencia se publican publicaciones en el tema utilizando el comando rostopic:rostopic hz image_raw
Este comando calcula la frecuencia de recepción de mensajes por tema cada segundo y lo muestra en la consola.Para el modelo B +, tuve una conclusión como esta:average rate: 7.905
min: 0.075s max: 0.249s std dev: 0.02756s
Como puede ver, la frecuencia de publicación es de 8 Hz.También verifiqué la frecuencia de publicación de imágenes de la cámara en el modelo RPi 2. Aquí los resultados fueron muchas veces mejores:average rate: 30.005
min: 0.024s max: 0.043s std dev: 0.00272s
Los mensajes ya se publican a una frecuencia de 30 Hz, que es un aumento bastante bueno en la velocidad en comparación con el modelo B +.Control de robot basado en visual con OpenCV y ROS
Ahora escribiremos un pequeño paquete ROS para usar la visión por computadora en un robot con Raspberry Pi, que realizará el algoritmo de reconocimiento (en nuestro caso, orientación visual usando el método de seguimiento de línea) y publicará el valor del desplazamiento del robot requerido al tema. Por otro lado, el nodo de control de movimiento del robot se suscribirá a este tema y enviará comandos de control de movimiento al Arduino.Ahora agreguemos un "editor" al script capturer.cpp, que publicará el valor del turno. Primero, habilite la definición del tipo de mensaje para el valor de cambio: std_msgs / Int16.#include <std_msgs/Int16.h>
rosserial toma archivos especiales de mensajes msg y genera código fuente para ellos. Se utiliza esta plantilla: el código fuente de los mensajes rosseriales estándar se almacena en la carpeta nombre_paquete dentro del directorio ros_lib. A continuación, inicializamos el mensaje para este tipo:package_name/msg/Foo.msg → package_name::Foo
std_msgs::Int16 shift_msg;
Crear un "editor":ros::Publisher shift_pub;
y dentro del constructor UsbCamNode le damos una definición:shift_pub = nh.advertise<std_msgs/Int16>(“line_shift”, 1);
Aquí establecemos el tipo de mensajes y el nombre del tema para su publicación.Luego, agregue la lógica para calcular el valor de cambio de línea usando OpenCV y publíquelo en el tema line_shift en el método take_and_send_image () antes de la línea #ifdef OUTPUT_ENABLED:
shift_msg.data = offset;
shift_pub.publish(shift_msg);
No tengo un algoritmo de seguimiento de línea listo, por lo que el lector es libre de escribir aquí su propia lógica.De hecho, los datos en el mensaje se almacenan en el campo de datos. La estructura del mensaje se puede ver con el comando:$ rosmsg show std_msgs/Int16
Ahora ejecuta el nodo:$ rosrun raspi_cam_ros capturer
Utilizamos el comando rostopic echo para generar datos publicados en el tema line_shift:$ rostopic echo line_shift
Ahora agregue un "suscriptor" al nodo de control del robot. Habilite la definición del tipo de mensaje:#include <std_msgs/UInt16.h>
Luego agregamos una función de devolución de llamada que se ejecuta cuando se recibe un mensaje del tema.void messageCb(const std_msgs::UInt16& message)
{
int shift_val = int(message.data);
char* log_msg;
if(shift_val < 0) log_msg = "Left";
else if(shift_val > 0 ) log_msg = "Right";
else log_msg = "Forward";
nh.loginfo(log_msg);
}
La función de devolución de llamada debe ser de tipo void y tomar una referencia constante del tipo de mensaje como argumento.Para simplificar, registro un mensaje sobre la dirección del desplazamiento de línea. Aquí puede agregar su propia lógica de movimiento de robot para su escenario.Cree un suscriptor a los mensajes del tema line_shift.ros::Subscriber<std_msgs::UInt16> sub("line_shift", &messageCb);
Aquí establecemos el nombre del tema y un enlace a la función de devolución de llamada.Luego vienen los métodos de boceto estándar para rosserial_arduino:void setup()
{
nh.initNode();
nh.subscribe(sub);
Serial.begin(57600);
}
void loop()
{
nh.spinOnce();
delay(100);
}
La única diferencia es que agregamos nh.subscribe (sub) para crear la "suscripción" real del sitio al tema.Un boceto para controlar un robot se puede descargar desde aquí .Pequeño truco! En ROS, hay archivos de inicio especiales que le permiten iniciar nodos como procesos separados automáticamente con ciertos parámetros. los archivos de inicio se crean en formato xml y su sintaxis le permite ejecutar muchos nodos a la vez. Sin embargo, el archivo de inicio no garantiza que los nodos se iniciarán en el orden exacto especificado.Puede crear un archivo de inicio para facilitar el inicio del servidor rosserial_python.$ cd <catkin_ws>/src
$ catkin_create_pkg rosserial_controller
$ cd src/rosserial_controller
$ vim rosserial_controller.launch
Escribimos el archivo de inicio con el siguiente contenido:<launch>
<node pkg="rosserial_python" type="serial_node.py" name="arduino_serial">
<param name="port" value="/dev/ttyACM0"/>
</node>
</launch>
Compilar y ejecutarlo:$ cd ~/<catkin_ws>
$ catkin_make
$ source devel/setup.bash
$ roslaunch rosserial_controller rosserial_controller.launch
Podemos visualizar los valores publicados en el tema line_shift usando la utilidad rqt_plot, como se hace en el artículo :$ rqt_plot line_shift
Ahora puede aprovechar al máximo la cámara Raspberry Pi y la biblioteca OpenCV en sus escenarios para la orientación visual del robot, el reconocimiento de objetos, el seguimiento y muchos otros. ¡Desata tu imaginación!La próxima vez hablaremos sobre el control del robot en modo de teleoperación presionando las teclas del teclado.PS. La red tiene hojas de trucos útiles: ROS Cheatsheet. Para la versión ROS Indigo, esto se puede descargar desde aquí .