Workshop ROS 2016: analisando a tarefa de controle seguro do robô

Boa tarde, querido habratchiteli! Sexta-feira passada, em nosso laboratório, houve um workshop prático sobre a plataforma ROS - workshop ROS. O workshop foi organizado para estudantes da Faculdade de Tecnologia da Informação da Universidade Técnica de Brno que desejam se familiarizar com esta plataforma. Diferentemente dos anos anteriores (o workshop foi realizado por 4 anos), desta vez o workshop do ROS foi focado no trabalho prático independente. Neste artigo, vou falar sobre a tarefa que foi definida para os participantes do workshop. Quem se importa, por favor, debaixo do gato.

imagem

Declaração do problema


Os participantes foram encarregados de implementar o controle seguro do robô com uma parada na frente de obstáculos. O objetivo da tarefa é controlar a velocidade do robô na direção para frente. O robô recebe dados do sensor de profundidade (no nosso caso, o ASUS Xtion no simulador turtlebot_gazebo), encontra o obstáculo mais próximo na direção do movimento e determina três zonas:

  • Seguro - o robô a uma distância segura, se move sem desaceleração
  • Aviso - o robô se aproxima de um obstáculo, emite um sinal de aviso (por exemplo, um sinal de áudio) e diminui a velocidade
  • Perigo - o obstáculo está muito próximo, o robô para

Implementação


Percebo imediatamente que, no workshop, o ROS Indigo no Ubuntu 14.04 foi usado para concluir a tarefa. Eu também usei o ROS Indigo para experimentos.

Então, vamos começar! Crie um pacote com as dependências roscpp, pcl_ros, pcl_conversions, sensor_msgs e geometry_msgs:

cd ~/catkin_ws/src
catkin_create_pkg safety_control_cloud roscpp pcl_ros pcl_conversions sensor_msgs geometry_msgs
cd ~/catkin_ws

Adicione a biblioteca PCL ao package.xml, dependendo de:

<build_depend>libpcll-all-dev</build_depend>
...
<run_depend>libpcl-all</run_depend>


e no CMakeLists.txt:

find_package(PCL REQUIRED)
...
include_directories(${PCL_INCLUDE_DIRS})

Adicione o script safety_control.cpp à pasta 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)
{
  /**
   * The ros::init() function needs to see argc and argv so that it can perform
   * any ROS arguments and name remapping that were provided at the command line.
   * For programmatic remappings you can use a different version of init() which takes
   * remappings directly, but for most command-line programs, passing argc and argv is
   * the easiest way to do it.  The third argument to init() is the name of the node.
   *
   * You must call one of the versions of ros::init() before using any other
   * part of the ROS system.
   */
  ros::init(argc, argv, "safety_control_cloud");

  /**
   * NodeHandle is the main access point to communications with the ROS system.
   * The first NodeHandle constructed will fully initialize this node, and the last
   * NodeHandle destructed will close down the node.
   */
  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;
}


Adicione o script safety_control.cpp ao CMakeLists.txt:

add_executable(safety_control_node src/safety_control.cpp)
target_link_libraries(safety_control_node ${catkin_LIBRARIES} ${PCL_LIBRARIES})

Na lógica do nó, assinamos os dados do tópico / câmera / profundidade / pontos, obtemos uma nuvem de pontos, calculamos as coordenadas do ponto mais próximo do sensor de profundidade na nuvem de pontos e, dependendo da situação, publicamos a velocidade linear como geometry_msgs / Twister no tópico / cmd_vel_mux / input / teleop .

Também precisamos cortar a nuvem de pontos em vários eixos em um determinado intervalo para um processamento mais eficiente. Nas seguintes linhas:


    pcl::PassThrough<PointType> pass;
    pass.setInputCloud(pcd_pcl);
    pass.setFilterFieldName("y");
    pass.setFilterLimits(-0.25,0.20);
    pass.filter(*pcd_filtered);

corte a nuvem usando o método PassThrough 25 cm para baixo e 20 cm para cima a partir da origem do sistema de coordenadas do sensor de profundidade (ao longo do eixo y).

Nas linhas:


pass.setInputCloud(pcd_filtered);
pass.setFilterFieldName("x");
pass.setFilterLimits(-0.3,0.3);
pass.filter(*pcd_pcl);

Cortamos a nuvem 0,3 m (30 cm) à esquerda e à direita da origem do sistema de coordenadas do sensor (eixo z). Em seguida, procuramos o ponto mais próximo na nuvem de pontos ao longo do eixo z (o eixo do centro do sensor de profundidade na direção da visão) - este será o ponto do objeto mais próximo:


pcl::getMinMax3D(*pcd_pcl, pt_min, pt_max);

A velocidade também será publicada no tópico / mobile_base / command / velocity. Compile o pacote:

cd ~/catkin_ws
catkin_make
source devel/setup.bash

Testes no simulador Turtle Bot no Gazebo


A segunda tarefa foi testar a lógica de controle do robô com o simulador TurtleBot no Gazebo. Para fazer isso, configure turtlebot_gazebo usando o apt-get:

sudo apt-get install ros-indigo-turtlebot*

Aqui você pode encontrar alguns tutoriais úteis sobre o uso do simulador. Um simulador pode ser uma boa solução quando você deseja estudar pacotes de navegação no ROS e não há um robô real em mãos. Execute o simulador:

roslaunch turtlebot_gazebo turtlebot_world.launch

A janela do Gazebo será aberta como na figura:

imagem

Podemos ampliar e reduzir a imagem com a roda do mouse. Usando o botão esquerdo do mouse e o cursor, podemos mover a imagem para a esquerda, direita, para cima e para baixo. Usando a roda do mouse e o cursor fixos, você pode alterar o ângulo de visão vertical. Agora vire o robô para que ele olhe diretamente para o gabinete. Na linha superior de ferramentas acima da janela de visualização da simulação, selecione o terceiro ícone:

imagem

E clique nele. Vamos ver algo assim:

imagem

vire o robô clicando e puxando o arco azul. Temos a seguinte imagem:

imagem

Run rviz:

rosrun rviz rviz

Adicione uma exibição RobotModel, conforme já descrito no artigo . Adicione uma exibição do PointCloud2 e selecione o tópico / câmera / profundidade / pontos. Como resultado, obtemos a seguinte imagem:

imagem

Para a exibição PointCloud2, selecione RGB8 para o campo Transformador de cores. Temos uma nuvem de pontos em cores:

imagem

Execute nosso nó safety_control_node:

rosrun safety_control_cloud safety_control_node

A saída no terminal será assim:

[ INFO] [1479229421.537897080, 2653.960000000]: Point cloud arrived
[ INFO] [1479229421.572338588, 2654.000000000]: Warning zone
[ INFO] [1479229421.641967924, 2654.070000000]: Warning zone

Vamos listar os tópicos:

rostopic list

Entre os tópicos, veremos:

/cmd_vel_mux/input/teleop
...
/mobile_base/commands/velocity

Mostrar mensagens no tópico / mobile_base / command / velocity:

rostopic echo /mobile_base/commands/velocity

Obtenha a velocidade do robô:

linear: 
  x: 0.1
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---

O robô se moverá em direção ao gabinete e finalmente parará ao lado do gabinete na zona de perigo. No Gazebo, veremos uma parada completa do robô:

imagem

Na saída do nó safety_control_node, veremos as mensagens:

[ INFO] [1479229426.604300460, 2658.980000000]: Danger zone
[ INFO] [1479229426.717093096, 2659.100000000]: Danger zone

E no tópico / mobile_base / command / velocity, uma mensagem com velocidade zero será agora publicada:

linear: 
  x: 0.0
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---

Inclua uma exibição do tipo PointCloud2 com o tópico / output em rviz. Para a tela Color Transformer, selecione FlatColor e verde no campo Color. Esta será a nossa seção da nuvem de pontos do nó safety_control_node: Vamos

imagem

mover o robô ainda mais longe, a uma distância segura do obstáculo. Para fazer isso, clique no segundo ícone na parte superior:

imagem

e mova o robô arrastando-o com o cursor:

imagem

No rviz, veremos o seguinte:

imagem

Receberemos essas mensagens do nosso nó:

[ INFO] [1479230429.902116395, 3658.000000000]: Safe zone
[ INFO] [1479230429.992468971, 3658.090000000]: Safe zone

A velocidade do robô será assim:

---                                                                                                                                                                                 
linear: 
  x: 0.2
  y: 0.0
  z: 0.0
angular: 
  x: 0.0
  y: 0.0
  z: 0.0
---

Além disso, tudo o que foi descrito acima será repetido: desaceleração na zona de aviso e parada perto do gabinete.

Agora, nosso TurtleBot é capaz de parar diante de qualquer obstáculo que o sensor de profundidade possa detectar (ASUS Xtion no caso de ROS Indigo). Você pode tentar o programa de controle em um robô real equipado com um sensor como o Microsoft Kinect.

Só isso. Escrevemos um programa simples para controlar a velocidade do robô usando dados de um sensor de profundidade - uma nuvem de pontos - e o testamos no simulador de robô TurtleBot no Gazebo.

Boa sorte nos experimentos e até breve!

Source: https://habr.com/ru/post/pt399151/


All Articles