Bonjour, chers lecteurs de Habr! Il s'agit du deuxième article d'une série d'articles sur l'utilisation pratique de ROS sur le Raspberry Pi. Dans le premier article de la série, j'ai décrit l'installation des composants ROS nécessaires et la configuration de l'environnement de travail pour le travail.Dans la deuxième partie de la série, nous commencerons à utiliser concrètement les fonctionnalités ROS sur la plate-forme Raspberry Pi. Plus précisément, dans cet article, je vais parler de l'utilisation de la carte de caméra Raspberry Pi sur le Raspberry Pi en conjonction avec ROS pour résoudre les problèmes de vision par ordinateur. Qui est intéressé, s'il vous plaît, sous cat.Camera RPi Camera Board
Pour le travail, nous aurons besoin d'une telle caméra Raspberry Pi Camera Board:
cette caméra se connecte directement au GPU via un connecteur CSi sur la carte, ce qui vous permet d'enregistrer et de coder l'image de la caméra sans utiliser le temps du processeur. Un câble ZIF est utilisé pour connecter l'appareil photo. Le connecteur de câble sur la carte est situé entre les ports Ethernet et HDMI:
Installation de la bibliothèque
Continuons donc à installer les bibliothèques nécessaires. Tout d'abord, installez OpenCV:$ sudo apt-get install libopencv-dev
Pour utiliser la caméra Raspberry Pi, nous aurons besoin de la bibliothèque raspicam. Téléchargez l'archive d'ici .Ensuite, installez la bibliothèque:$ tar xvzf raspicamxx.tgz
$ cd raspicamxx
$ mkdir build
$ cd build
$ cmake ..
$ make
$ sudo make install
$ sudo ldconfig
Vous devez activer la prise en charge des caméras dans Raspbian via le programme raspi-config:$ sudo raspi-config
Sélectionnez l'option 5 - Activer la caméra, enregistrez la sélection et redémarrez le système.Premiers pas avec ROS
Pour plus de commodité, créez un nouvel atelier chatons pour nos packages:$ mkdir -p ~/driverobot_ws/src
$ cd ~/driverobot_ws/src
$ catkin_init_workspace
$ cd ~/driverobot_ws
$ catkin_make
Créez un nouveau package ROS:$ cd src/
$ catkin_create_pkg raspi_cam_ros image_transport cv_bridge roscpp std_msgs sensor_msgs compressed_image_transport opencv2
La spécification de la commande catkin_create_pkg est la suivante: catkin_create_pkg <package_name> [depend1] [depend2],où vous pouvez spécifier toutes les dépendances sous la bibliothèque - les bibliothèques que le package utilisera.Cette commande crée le cadre du projet ROS: un répertoire src vide pour les scripts de noeud et les fichiers de configuration CMakeLists.txt et package.xml.J'ai trouvé un script simple qui reçoit les images de la caméra et les publie en utilisant «l'éditeur» (éditeur), et je l'ai adapté pour ROS Indigo. Vous pouvez le télécharger ici .Pour l'utiliser, vous devez installer le pilote de la caméra Raspberry Pi UV4L:$ curl http://www.linux-projects.org/listing/uv4l_repo/lrkey.asc | sudo apt-key add -
Ajoutez la ligne suivante au fichier /etc/apt/sources.listdeb http://www.linux-projects.org/listing/uv4l_repo/raspbian/ wheezy main
mettre à jour les packages et installer:$ sudo apt-get update
$ sudo apt-get install uv4l uv4l-raspicam
Pour télécharger le pilote, à chaque démarrage du système, nous installons également un package optionnel:$ sudo apt-get install uv4l-raspicam-extras
Passons à l'édition du package. Collez les lignes d'ici dans votre fichier CMakeLists.txt .Les lignes les plus importantes du fichier CMakeLists.txt:link_directories(/usr/lib/uv4l/uv4lext/armv6l/)
…
target_link_libraries(capture ${catkin_LIBRARIES} uv4lext)
Ainsi, nous ajoutons un lien vers le pilote uv4l, qui est nécessaire pour compiler le package.À la fin du fichier, nous définissons des lignes spéciales pour notre nœud:add_executable(capture src/capturer.cpp)
target_link_libraries(capture ${catkin_LIBRARIES} uv4lext)
La ligne add_executable crée un binaire pour le lancement et target_link_lbraries relie des bibliothèques supplémentaires pour le binaire de capture.Collez les lignes manquantes d'ici dans le fichier package.xml pour qu'il ressemble à ceci:<?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>
Dans les premières lignes, les paramètres de base du nœud sont définis - nom, version, description, informations sur l'auteur. Les lignes build_depend déterminent les dépendances de bibliothèque nécessaires pour compiler le package, et les lignes run_depend déterminent les dépendances nécessaires pour exécuter le code dans le package.Créez un fichier capturer.cpp dans le dossier src et collez les lignes à partir d'ici . Ici, dans la méthode main (), le nœud est initialisé et démarré en boucle:ros::init(argc, argv,"raspi_cam_ros");
ros::NodeHandle n;
UsbCamNode a(n);
a.spin();
Toute la logique du script est que nous obtenons l'image de la caméra en utilisant OpenCV, l'enveloppons dans un message pour ROS dans la méthode fillImage et la publions dans le sujet. Ici, le package image_transport est utilisé pour créer une image «éditeur».Lancez le pilote uv4l en exécutant la commande:$ uv4l --driver raspicam --auto-video_nr --width 640 --height 480 --nopreview
ce qui créera le streaming MJPEG.Compilez notre nœud ROS:$ roscore
$ cd ~/driverobot_ws
$ catkin_make
Vérifiez la valeur de la variable ROS_PACKAGE_PATH:echo $ROS_PACKAGE_PATH
/opt/ros/indigo/share:/opt/ros/indigo/stacks
La valeur de la variable ROS_PACKAGE_PATH doit inclure le chemin d'accès à notre espace de travail. Ajoutez notre espace atelier au chemin:$ source devel/setup.bash
Maintenant, en exécutant à nouveau la commande echo $ ROS_PACKAGE_PATH, nous devrions voir une sortie similaire:/home/youruser/catkin_ws/src:/opt/ros/indigo/share:/opt/ros/indigo/stacks
, où / home / <nom_utilisateur> / catkin_ws / src est le chemin vers notre espace de travail. Cela signifie que ROS peut «voir» nos nœuds créés dans catkin_ws et nous pouvons les exécuter via rosrun.Exécutez notre nœud ROS:$ rosrun raspi_cam_ros capture
Exécutez le programme graphique rqt_image_view pour afficher le flux vidéo de la rubrique:$ rosrun rqt_image_view rqt_image_view
Sélectionnez la rubrique image_raw dans la fenêtre rqt_image_view.
Lors du démarrage du nœud, l'erreur «Gtk-WARNING **: impossible d'ouvrir l'affichage: -1» peut se produire lorsque vous travaillez via ssh ou «GdkGLExt-WARNING **: le système de fenêtres ne prend pas en charge OpenGL». lors de l'exécution en mode Bureau à distance VNC. La solution est de se connecter au Raspberry Pi via SSH avec redirection X11:$ ssh -X pi@<host_pi>
Vous pouvez savoir à quelle fréquence les publications sont publiées sur le sujet à l'aide de la commande rostopic:rostopic hz image_raw
Cette commande calcule la fréquence de réception des messages par sujet chaque seconde et l'affiche dans la console.Pour le modèle B +, j'avais une conclusion comme celle-ci:average rate: 7.905
min: 0.075s max: 0.249s std dev: 0.02756s
Comme vous pouvez le voir, la fréquence de publication est de 8 Hz.J'ai également vérifié la fréquence de publication des images de la caméra sur le modèle RPi 2. Ici, les résultats étaient bien meilleurs:average rate: 30.005
min: 0.024s max: 0.043s std dev: 0.00272s
Les messages sont déjà publiés à une fréquence de 30 Hz, ce qui représente une assez bonne augmentation de la vitesse par rapport au modèle B +.Contrôle robotique basé sur le visuel avec OpenCV et ROS
Nous allons maintenant écrire un petit package ROS pour utiliser la vision par ordinateur sur un robot avec le Raspberry Pi, qui exécutera l'algorithme de reconnaissance (dans notre cas, l'orientation visuelle en utilisant la méthode de suivi de ligne) et publiera la valeur du décalage de robot requis dans le sujet. D'un autre côté, le nœud de contrôle de mouvement du robot s'abonnera à ce sujet et enverra des commandes de contrôle de mouvement à l'Arduino.Ajoutons maintenant un «éditeur» au script capturer.cpp, qui publiera la valeur de décalage. Tout d'abord, activez la définition du type de message pour la valeur de décalage - std_msgs / Int16.#include <std_msgs/Int16.h>
rosserial prend des fichiers de messages msg spéciaux et génère du code source pour eux. Le modèle suivant est utilisé: Le code source des messages rosserial standard est stocké dans le dossier package_name dans le répertoire ros_lib. Ensuite, nous initialisons le message pour ce type:package_name/msg/Foo.msg → package_name::Foo
std_msgs::Int16 shift_msg;
Créer un «éditeur»:ros::Publisher shift_pub;
et à l'intérieur du constructeur UsbCamNode, nous lui donnons une définition:shift_pub = nh.advertise<std_msgs/Int16>(“line_shift”, 1);
Ici, nous définissons le type de messages et le nom du sujet à publier.Ensuite, ajoutez la logique pour calculer la valeur de décalage de ligne à l'aide d'OpenCV et la publier dans la rubrique line_shift dans la méthode take_and_send_image () avant la ligne #ifdef OUTPUT_ENABLED:
shift_msg.data = offset;
shift_pub.publish(shift_msg);
Je n'ai pas d'algorithme de suivi de ligne prêt à l'emploi, le lecteur est donc libre d'écrire sa propre logique ici.En fait, les données du message sont stockées dans le champ de données. La structure du message peut être visualisée à l'aide de la commande:$ rosmsg show std_msgs/Int16
Exécutez maintenant le nœud:$ rosrun raspi_cam_ros capturer
Nous utilisons la commande rostopic echo pour sortir les données publiées dans le sujet line_shift:$ rostopic echo line_shift
Ajoutez maintenant un «abonné» au nœud de contrôle du robot. Activez la définition du type de message:#include <std_msgs/UInt16.h>
Ensuite, nous ajoutons une fonction de rappel qui est exécutée lorsqu'un message est reçu de la rubrique.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 fonction de rappel doit être de type void et prendre une référence const du type de message comme argument.Par souci de simplicité, j'enregistre un message sur la direction du décalage de ligne. Ici, vous pouvez ajouter votre propre logique de mouvement de robot pour votre scénario.Créez un abonné aux messages de la rubrique line_shift.ros::Subscriber<std_msgs::UInt16> sub("line_shift", &messageCb);
Ici, nous définissons le nom du sujet et un lien vers la fonction de rappel.Viennent ensuite les méthodes d'esquisse standard pour rosserial_arduino:void setup()
{
nh.initNode();
nh.subscribe(sub);
Serial.begin(57600);
}
void loop()
{
nh.spinOnce();
delay(100);
}
La seule différence est que nous ajoutons nh.subscribe (sub) pour créer le véritable «abonnement» du site au sujet.Un croquis pour contrôler un robot peut être téléchargé ici .Petit truc! Dans ROS, il existe des fichiers de lancement spéciaux qui vous permettent de lancer automatiquement des nœuds en tant que processus séparés avec certains paramètres. les fichiers de lancement sont créés au format xml et leur syntaxe vous permet d'exécuter plusieurs nœuds à la fois. Cependant, le fichier de lancement ne garantit pas que les nœuds seront lancés dans l'ordre exact spécifié.Vous pouvez créer un fichier de lancement pour faciliter le démarrage du serveur rosserial_python.$ cd <catkin_ws>/src
$ catkin_create_pkg rosserial_controller
$ cd src/rosserial_controller
$ vim rosserial_controller.launch
Nous écrivons un fichier de lancement avec le contenu suivant:<launch>
<node pkg="rosserial_python" type="serial_node.py" name="arduino_serial">
<param name="port" value="/dev/ttyACM0"/>
</node>
</launch>
Compilez-le et exécutez-le:$ cd ~/<catkin_ws>
$ catkin_make
$ source devel/setup.bash
$ roslaunch rosserial_controller rosserial_controller.launch
Nous pouvons visualiser les valeurs publiées dans le thème line_shift à l'aide de l'utilitaire rqt_plot, comme cela est fait dans l' article :$ rqt_plot line_shift
Vous pouvez maintenant profiter pleinement de la caméra Raspberry Pi et de la bibliothèque OpenCV dans vos scripts pour l'orientation visuelle du robot, la reconnaissance d'objets, le suivi et bien d'autres. Laissez libre cours à votre imagination!La prochaine fois, nous parlerons de la commande du robot en mode téléopération en appuyant sur les touches du clavier.PS. Le réseau a des astuces utiles - ROS Cheatsheet. Pour la version ROS Indigo, celle-ci peut être téléchargée ici .