ROS szenzoradatok feldolgozása C++ node-al
Tartalom
- A feladat
- Előkészületek
- Rviz
- Package és node készítése egyszerű LIDAR szűrésre, vizualizációra
- A node-ok futtatása
A feladat leírása
Első feladatunk, hogy 3D LIDAR szenzoradatokat tartalmazó rosbag-et játszunk vissza és az adatokon egyszerű akadályfelismerést valósítsunk meg, majd ezt vizualizáljuk. Az akdadályfelismerés naiv, de sokszor működőképes módja, hogy a jármű előtt egy virtuális téglatestben vizsgáljuk, hogy van-e objektumot reprezentáló voxel (3d pixel) / 3d pont. Ezt vizualizáljuk úgy, hogy a kijelölt téglatesbe eső voxeleket külön point cloud-ként hirdessük, illetve a téglatestet is jelöljük zöld illetve piros színnel. Erről illusztráció:
Előkészületek
Az előző gyakorlatok után továbbhaladva, azok eredményeit felhasználva lépünk tovább. Töltsük le a több szenzoradatot is tartalmazó rosbag fájlt.
cd ~/rosbag-gyak
wget www.sze.hu/~herno/PublicDataAutonomous/leaf-2019-09-12-15-10-46-gps-lidar-zala.bag
wget https://raw.githubusercontent.com/horverno/ros-gyakorlatok/master/3-ros-node-szenzoradatok/leaf-v1.rviz
Jelenítsük meg az információkat.
rosbag info leaf-2019-09-12-15-10-46-gps-lidar-zala.bag
Leginkább 2 topic lesz számunkra fontos:
/points_raw 182 msgs : sensor_msgs/PointCloud2
/scan 482 msgs : sensor_msgs/LaserScan
$ rosmsg info sensor_msgs/PointCloud2
std_msgs/Header header
uint32 seq
time stamp
string frame_id
uint32 height
uint32 width
sensor_msgs/PointField[] fields
uint8 INT8=1
uint8 UINT8=2
uint8 INT16=3
uint8 UINT16=4
uint8 INT32=5
uint8 UINT32=6
uint8 FLOAT32=7
uint8 FLOAT64=8
string name
uint32 offset
uint8 datatype
uint32 count
bool is_bigendian
uint32 point_step
uint32 row_step
uint8[] data
bool is_dense
$ rosmsg info sensor_msgs/LaserScan
std_msgs/Header header
uint32 seq
time stamp
string frame_id
float32 angle_min
float32 angle_max
float32 angle_increment
float32 time_increment
float32 scan_time
float32 range_min
float32 range_max
float32[] ranges
float32[] intensities
rviz
Jelenítsük meg rviz segítségével az adatokat, roscore
indítása és rosbag
visszajátszás után után:
rosbag play -l leaf-2019-09-12-15-10-46-gps-lidar-zala.bag
Megjelenítés rviz
-zel:
rosrun rviz rviz -d ~/rosbag-gyak/leaf-v1.rviz
Package és node készítése egyszerű LIDAR szűrésre, vizualizációra
Készítsük el a gyakorló workspace-t:
cd ~ ; mkdir -p gyak_ws/src ; cd gyak_ws/src
Majd ebben a packaget:
catkin create pkg lidar_tutorial --catkin-deps roscpp pcl_conversions pcl_ros sensor_msgs visualization_msgs
Indítsuk a VS code-t (code .
parancs)
Mentsük le a 3 cpp fájlt:
cd ~/gyak_ws/src/lidar_tutorial/src ; wget https://raw.githubusercontent.com/horverno/ros-gyakorlatok/master/3-ros-node-szenzoradatok/lidar_and_marker.cpp ; wget https://raw.githubusercontent.com/horverno/ros-gyakorlatok/master/3-ros-node-szenzoradatok/lidar_filter.cpp ; wget https://raw.githubusercontent.com/horverno/ros-gyakorlatok/master/3-ros-node-szenzoradatok/pub_marker.cpp
A VS code automatikus kiegészítés funkciója akkor működik jól, a hiányzónak jelölt incudenál, (pl. ros/ros.h
), kattintsunk a sárga villanykörte ikonra, majd Edit "includepath" settings
részre megyünk és az Include path
mezőbe a következőket írjuk:
${workspaceFolder}/**
/opt/ros/melodic/include
/opt/ros/melodic/include/pcl
/usr/include
/usr/include/pcl-1.7
/usr/include/eigen3
Megjegyzés a későbbiekben (AutoWare használatakor) hasznos lehet még a következő is:
~/autoware_ws/Autoware/ros/devel/include
A CMakeLists.txt
végére a következőket írjuk:
add_executable(publish_marker src/pub_marker.cpp)
target_link_libraries(publish_marker ${catkin_LIBRARIES})
add_executable(basic_lidar_filter src/lidar_filter.cpp)
target_link_libraries(basic_lidar_filter ${catkin_LIBRARIES})
add_executable(lidar_and_marker src/lidar_and_marker.cpp)
target_link_libraries(lidar_and_marker ${catkin_LIBRARIES})
Lépjünk vissza a workspace-be (cd ~/gyak_ws
), majd buildeljünk:
catkin build
Szerkesszük a ~/.bashrc
-t (code ~/.bashrc
)
source ~/gyak_ws/devel/setup.bash
Az egyszerű filter (lidar_filter.cpp
) tartalma a következő:
#include <ros/ros.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/crop_box.h>
ros::Publisher pub;
ros::Publisher marker_pub;
void cloud_cb(const pcl::PCLPointCloud2ConstPtr &cloud)
{
pcl::PCLPointCloud2 cloud_filtered;
// Define min and max for X, Y and Z
float minX = 0.0, minY = -1.0, minZ = -1.384;
float maxX = 16.0, maxY = +1.0, maxZ = -0.15;
pcl::CropBox<pcl::PCLPointCloud2> boxFilter;
boxFilter.setMin(Eigen::Vector4f(minX, minY, minZ, 1.0));
boxFilter.setMax(Eigen::Vector4f(maxX, maxY, maxZ, 1.0));
boxFilter.setInputCloud(cloud);
boxFilter.filter(cloud_filtered);
if(cloud_filtered.data.size() > 10)
ROS_WARN_STREAM("Object in the selected area");
// Publish the filtered LIDAR data
pub.publish(cloud_filtered);
}
int main(int argc, char **argv)
{
// Initialize ROS
ros::init(argc, argv, "lidar_filt");
ros::NodeHandle nh;
// Create a ROS subscriber for the input point cloud
ros::Subscriber sub = nh.subscribe("points_raw", 1, cloud_cb);
// Create a ROS publisher for the output point cloud
pub = nh.advertise<pcl::PCLPointCloud2>("points_filt", 1);
// Spin
ros::spin();
}
Magyarázat: A main
-ben feliratkozunk a points_raw
topicra, ami a nyers LIDAR adatokat tartalmazza, valamint elkezdjük hirdetni a points_filt
topicot, ebbe kerülnek majd a megszűrt adatok. A cloud_cb
függvény végzi a szűrést és a ROS_WARN_STREAM
segítségével jelez, amennyiben objektum van a kijelölt területen. A cloud_filtered.data.size() > 10
azt jelenti, hogy a szűrt pontfelhő elemszáma nagyobb-e mint 10 voxel (3d pont).
A node-ok futtatása
A egyszerű LIDAR filter node így indítható:
rosrun lidar_tutorial basic_lidar_filter
A marker publikáló node pedig így:
rosrun lidar_tutorial publish_marker
A filtert és a markert kombináló node:
rosrun lidar_tutorial lidar_and_marker