Buenas tardes, querido habratchiteli! El viernes pasado en nuestro laboratorio hubo un taller práctico sobre la plataforma ROS - taller ROS. El taller fue organizado para estudiantes de la Facultad de Tecnología de la Información de la Universidad Técnica de Brno que desean familiarizarse con esta plataforma. A diferencia de años anteriores (el taller se llevó a cabo durante 4 años), esta vez el taller ROS se centró en el trabajo práctico independiente. En este artículo voy a hablar sobre la tarea que se estableció para los participantes del taller. A quién le importa, por favor, debajo del gato.
Declaración del problema.
Los participantes tuvieron la tarea de implementar un control de robot seguro con una parada frente a los obstáculos. El objetivo de la tarea es controlar la velocidad del robot en la dirección de avance. El robot recibe datos del sensor de profundidad (en nuestro caso, ASUS Xtion en el simulador turtlebot_gazebo), encuentra el obstáculo más cercano en la dirección del movimiento y determina tres zonas:- Seguro: el robot a una distancia segura, se mueve sin desaceleración
- Advertencia: el robot se acerca a un obstáculo, emite una señal de advertencia (por ejemplo, una señal de audio) y disminuye la velocidad
- Peligro: el obstáculo está muy cerca, el robot se detiene
Implementación
Noto de inmediato que en el taller, se utilizó ROS Indigo en Ubuntu 14.04 para completar la tarea. También utilicé ROS Indigo para experimentos.¡Entonces comencemos! Cree un paquete con las dependencias roscpp, pcl_ros, pcl_conversions, sensor_msgs y geometry_msgs:cd ~/catkin_ws/src
catkin_create_pkg safety_control_cloud roscpp pcl_ros pcl_conversions sensor_msgs geometry_msgs
cd ~/catkin_ws
Agregue la biblioteca PCL a package.xml dependiendo de:<build_depend>libpcll-all-dev</build_depend>
...
<run_depend>libpcl-all</run_depend>
y en CMakeLists.txt:find_package(PCL REQUIRED)
...
include_directories(${PCL_INCLUDE_DIRS})
Agregue el script safety_control.cpp a la carpeta src:safety_control.cpp#include "ros/ros.h"
#include "pcl_conversions/pcl_conversions.h"
#include <pcl/pcl_base.h>
#include <sstream>
#include <sensor_msgs/PointCloud2.h>
#include <pcl/filters/passthrough.h>
#include <pcl/common/common.h>
#include <geometry_msgs/Twist.h>
typedef pcl::PointXYZ PointType;
typedef pcl::PointCloud<PointType> PointCloud;
typedef PointCloud::Ptr PointCloudPtr;
ros::Publisher pcd_pub_, cmd_vel_pub_;
void pcd_cb(const sensor_msgs::PointCloud2ConstPtr& pcd) {
ROS_INFO_STREAM_ONCE("Point cloud arrived");
PointCloudPtr pcd_pcl = PointCloudPtr(new PointCloud), pcd_filtered = PointCloudPtr(new PointCloud);
PointType pt_min, pt_max;
pcl::fromROSMsg(*pcd, *pcd_pcl);
pcl::PassThrough<PointType> pass;
pass.setInputCloud(pcd_pcl);
pass.setFilterFieldName("y");
pass.setFilterLimits(-0.25,0.20);
pass.filter(*pcd_filtered);
pass.setInputCloud(pcd_filtered);
pass.setFilterFieldName("x");
pass.setFilterLimits(-0.3,0.3);
pass.filter(*pcd_pcl);
pcl::getMinMax3D(*pcd_pcl, pt_min, pt_max);
geometry_msgs::Twist vel;
if (pt_min.z > 1.0) {
vel.linear.x = 0.2;
ROS_INFO_STREAM("Safe zone");
} else if (pt_min.z > 0.5) {
vel.linear.x = 0.1;
ROS_INFO_STREAM("Warning zone");
} else {
vel.linear.x = 0.0;
ROS_INFO_STREAM("Danger zone");
}
cmd_vel_pub_.publish(vel);
sensor_msgs::PointCloud2 pcd_out;
pcl::toROSMsg(*pcd_pcl, pcd_out);
pcd_pub_.publish(pcd_out);
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "safety_control_cloud");
ros::NodeHandle n;
ros::Subscriber pcd_sub = n.subscribe("/camera/depth/points", 1, pcd_cb);
pcd_pub_ = n.advertise<sensor_msgs::PointCloud2>("/output", 1);
cmd_vel_pub_ = n.advertise<geometry_msgs::Twist>("/cmd_vel_mux/input/teleop", 1);
ros::spin();
return 0;
}
Agregue el script safety_control.cpp a CMakeLists.txt:add_executable(safety_control_node src/safety_control.cpp)
target_link_libraries(safety_control_node ${catkin_LIBRARIES} ${PCL_LIBRARIES})
En la lógica de nodo, suscribimos los datos del tema / cámara / profundidad / puntos, obtenemos una nube de puntos, calculamos las coordenadas del punto más cercano al sensor de profundidad en la nube de puntos y, según la situación, publicamos velocidad lineal como geometry_msgs / Twister en el tema / cmd_vel_mux / input / teleop .También necesitamos cortar la nube de puntos en varios ejes en un cierto rango para un procesamiento más eficiente. En las siguientes líneas:
pcl::PassThrough<PointType> pass;
pass.setInputCloud(pcd_pcl);
pass.setFilterFieldName("y");
pass.setFilterLimits(-0.25,0.20);
pass.filter(*pcd_filtered);
recorte la nube utilizando el método PassThrough 25 cm hacia abajo y 20 cm hacia arriba desde el origen del sistema de coordenadas del sensor de profundidad (a lo largo del eje y).En las lineas:
pass.setInputCloud(pcd_filtered);
pass.setFilterFieldName("x");
pass.setFilterLimits(-0.3,0.3);
pass.filter(*pcd_pcl);
Recortamos la nube 0.3 m (30 cm) a la izquierda y derecha del origen del sistema de coordenadas del sensor (eje z). Luego buscamos el punto más cercano en la nube de puntos a lo largo del eje z (el eje desde el centro del sensor de profundidad en la dirección de la vista): este será el punto del objeto más cercano:
pcl::getMinMax3D(*pcd_pcl, pt_min, pt_max);
La velocidad también se publicará en el tema / mobile_base / command / velocity. Compila el paquete:cd ~/catkin_ws
catkin_make
source devel/setup.bash
Pruebas en el simulador de Turtle Bot en Gazebo
La segunda tarea fue probar la lógica de control del robot con el simulador TurtleBot en Gazebo. Para hacer esto, configure turtlebot_gazebo usando apt-get:sudo apt-get install ros-indigo-turtlebot*
Aquí puede encontrar algunos tutoriales útiles sobre el uso del simulador. Un simulador puede ser una buena solución cuando desea estudiar paquetes de navegación en ROS y no hay un robot real a mano. Ejecuta el simulador:roslaunch turtlebot_gazebo turtlebot_world.launch
La ventana de Gazebo se abrirá como en la imagen:
podemos acercar y alejar la imagen con la rueda del mouse. Usando el botón izquierdo del mouse y el cursor podemos mover la imagen hacia la izquierda, derecha, arriba y abajo. Usando la rueda del mouse y el cursor, puede cambiar el ángulo de visión vertical. Ahora gire el robot para que mire directamente al gabinete. En la fila superior de herramientas sobre la ventana de visualización de simulación, seleccione el tercer icono:Y haz clic en él. Veremos algo como esto:
gire el robot haciendo clic y tirando del arco azul. Obtenemos la siguiente imagen:
Ejecutar rviz:rosrun rviz rviz
Agregue una pantalla RobotModel, como ya se describió en el artículo . Agregue una pantalla PointCloud2 y seleccione el tema / cámara / profundidad / puntos. Como resultado, obtenemos la siguiente imagen:
Para la pantalla PointCloud2, seleccione RGB8 para el campo Transformador de color. Obtenemos una nube de puntos en color:
ejecute nuestro nodo safety_control_node:rosrun safety_control_cloud safety_control_node
La salida en la terminal será así:[ INFO] [1479229421.537897080, 2653.960000000]: Point cloud arrived
[ INFO] [1479229421.572338588, 2654.000000000]: Warning zone
[ INFO] [1479229421.641967924, 2654.070000000]: Warning zone
Hagamos una lista de los temas:rostopic list
Entre los temas que veremos:/cmd_vel_mux/input/teleop
...
/mobile_base/commands/velocity
Mostrar mensajes en el tema / mobile_base / command / velocity:rostopic echo /mobile_base/commands/velocity
Obtén la velocidad del robot:linear:
x: 0.1
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0
---
El robot se moverá hacia el gabinete y finalmente se detendrá junto al gabinete en la zona de peligro. En Gazebo, veremos una parada completa del robot:
en la salida para el nodo safety_control_node, veremos los mensajes:[ INFO] [1479229426.604300460, 2658.980000000]: Danger zone
[ INFO] [1479229426.717093096, 2659.100000000]: Danger zone
Y en el tema / mobile_base / command / velocity ahora se publicará un mensaje con velocidad cero:linear:
x: 0.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0
---
Agregue una visualización de tipo PointCloud2 con el tema / output a rviz. Para la pantalla Transformador de color, seleccione FlatColor y verde en el campo Color. Esta será nuestra sección de la nube de puntos desde el nodo safety_control_node: vamos a
mover el robot aún más lejos, a una distancia segura del obstáculo. Para hacer esto, haga clic en el segundo icono en la parte superior:y mueva el robot arrastrándolo con el cursor:
En rviz veremos lo siguiente: Recibiremos
dichos mensajes de nuestro nodo:[ INFO] [1479230429.902116395, 3658.000000000]: Safe zone
[ INFO] [1479230429.992468971, 3658.090000000]: Safe zone
La velocidad del robot será así:---
linear:
x: 0.2
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0
---
Además, todo lo descrito anteriormente se repetirá: desaceleración en la zona de advertencia y detenerse cerca del gabinete.Ahora nuestro TurtleBot puede detenerse frente a cualquier obstáculo que el sensor de profundidad pueda detectar (ASUS Xtion en el caso de ROS Indigo). Puede probar el programa de control en un robot real equipado con un sensor como Microsoft Kinect.Eso es todo. Escribimos un programa simple para controlar la velocidad del robot hacia adelante utilizando datos de un sensor de profundidad, una nube de puntos, y lo probamos en el simulador de robot TurtleBot en Gazebo.¡Buena suerte en los experimentos y hasta pronto!