-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathpcl_to_gridmap.cpp
174 lines (140 loc) · 5.78 KB
/
pcl_to_gridmap.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include <cstring>
#include <hypergrid/gridmap.hpp>
#include <hypergrid/conversions/lidar_converter.hpp>
#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <nav_msgs/OccupancyGrid.h>
#include <tf/transform_listener.h>
// Map params
double map_height;
double map_width;
double cell_size;
bool DEBUG;
// Parameters for floor removal algorithm
bool floor_filter;
// Vehicle box to ignore points inside it
double vehicle_box_size;
// Maximum height of obstacles. Everything higher will out of the map
double max_height;
double heightmap_threshold;
double heightmap_cell_size;
// Laser frame to base_footprint tf transform
std::string map_frame_id;
std::string cloud_topic;
std::string output_topic;
ros::Publisher cloud_map_pub;
// Transform Listener
tf::TransformListener* tf_listener;
/* Removes all the points in the floor with a heightmap algorithm */
void remove_floor(af::array& cloud)
{
float* x = cloud(0, af::span).host<float>();
float* y = cloud(1, af::span).host<float>();
float* z = cloud(2, af::span).host<float>();
int height_cells = map_height / heightmap_cell_size;
int width_cells = map_width / heightmap_cell_size;
af::array x_arr = (width_cells / 2) + (cloud(0, af::span) / heightmap_cell_size);
af::array y_arr = (height_cells / 2) + (cloud(1, af::span) / heightmap_cell_size);
af::array z_arr = cloud(2, af::span);
float* min = new float[width_cells * height_cells];
float* max = new float[width_cells * height_cells];
// Resize the cloud to make it non-organized and work faster
int width = cloud.dims(0) * cloud.dims(1);
int height = 1;
// Init maps
for (int i = 0; i < width_cells; ++i)
{
for (int j = 0; j < height_cells; ++j)
{
int index = i * height_cells + j;
min[index] = 9999.9;
max[index] = -9999.9;
}
}
// Build height map
for (int i = 0; i < cloud.dims(1); ++i)
{
int x_idx = (width_cells / 2) + (x[i] / heightmap_cell_size);
int y_idx = (height_cells / 2) + (y[i] / heightmap_cell_size);
if (x_idx >= 0 && x_idx < width_cells && y_idx >= 0 && y_idx < height_cells)
{
int index = x_idx * height_cells + y_idx;
min[index] = std::min<float>(min[index], z[i]);
max[index] = std::max<float>(max[index], z[i]);
}
}
std::vector<int> indices;
for (int i = 0; i < width; ++i)
{
int x_idx = (width_cells / 2) + (x[i] / heightmap_cell_size);
int y_idx = (height_cells / 2) + (y[i] / heightmap_cell_size);
int index = x_idx * height_cells + y_idx;
bool is_obstacle = ((x_idx >= 0) && (x_idx < width_cells) && (y_idx >= 0) && (y_idx < height_cells)) && // Point is inside the grid
((z[i] < max_height)) && // Point is inside height limit
((abs(x[i]) > vehicle_box_size) || (abs(y[i]) > vehicle_box_size)) && // Point is not inside the vehicle box
((max[index] - min[index]) > heightmap_threshold); // Point is inside a cell considered obstacle by the heightmap
if (is_obstacle) indices.push_back(i);
}
af::array indices_arr(indices.size(), indices.data());
delete[] x;
delete[] y;
delete[] z;
delete[] min;
delete[] max;
cloud = af::lookup(cloud, indices_arr, 1);
}
void cloud_callback(sensor_msgs::PointCloud2Ptr cloud_msg)
{
ros::Time t0 = ros::Time::now();
ros::Time t_start = t0;
tf::StampedTransform pcl_footprint_transform;
try
{
tf_listener->lookupTransform(map_frame_id, cloud_msg->header.frame_id , ros::Time(0), pcl_footprint_transform);
}
catch(tf::TransformException &ex)
{
ROS_WARN("Warning: %s", ex.what());
}
geometry_msgs::Pose origin;
origin.position.x = - (map_width / 2) + cell_size;
origin.position.y = - (map_height / 2) + cell_size;
origin.orientation.w = 1;
hypergrid::LIDARConverter lidar_converter(map_width, map_height, cell_size,
origin, map_frame_id,
heightmap_threshold,
heightmap_cell_size,
max_height, vehicle_box_size,
DEBUG);
hypergrid::GridMap gridmap = lidar_converter.convert(cloud_msg, pcl_footprint_transform);
// Publish OccupancyGrid map
cloud_map_pub.publish(gridmap.toMapMsg());
if (DEBUG) std::cout << "Publish time: " << ros::Time::now() - t0 << std::endl;
if (DEBUG) std::cout << "Callback time: " << ros::Time::now() - t_start << std::endl;
}
int main(int argc, char **argv)
{
af::info();
ros::init(argc, argv, "pcl_to_gridmap");
ros::NodeHandle nh, priv_nh("~");
priv_nh.param<std::string>("map_frame_id", map_frame_id, "base_footprint");
priv_nh.param("height", map_height, 50.0);
priv_nh.param("width", map_width, 50.0);
priv_nh.param("cell_size", cell_size, 0.2);
priv_nh.param("floor_filter", floor_filter, false);
priv_nh.param("heightmap_threshold", heightmap_threshold, 0.15);
priv_nh.param("heightmap_cell_size", heightmap_cell_size, 0.25);
priv_nh.param("max_height", max_height, 2.5);
priv_nh.param("vehicle_box_size", vehicle_box_size, 2.0);
priv_nh.param("DEBUG", DEBUG, true);
cloud_map_pub = nh.advertise<nav_msgs::OccupancyGrid>("hypergrid/pcl_to_gridmap", 2);
ros::Subscriber cloud_sub = nh.subscribe("velodyne_points", 5, cloud_callback);
tf_listener = new tf::TransformListener();
ros::Rate r(10.0);
while(ros::ok())
{
ros::spinOnce();
r.sleep();
}
return 0;
}