datmo.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020, Robobrain.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Willow Garage, Inc. nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 /* Author: Konstantinos Konstantinidis */
31 
32 #include "datmo.hpp"
33 
35  ros::NodeHandle n;
36  ros::NodeHandle n_private("~");
37  ROS_INFO("Starting Detection And Tracking of Moving Objects");
38 
39  n_private.param("lidar_frame", lidar_frame, string("base_link"));
40  n_private.param("world_frame", world_frame, string("map"));
41  ROS_INFO("The lidar_frame is: %s and the world frame is: %s", lidar_frame.c_str(), world_frame.c_str());
42  n_private.param("threshold_distance", dth, 0.2);
43  n_private.param("max_cluster_size", max_cluster_size, 360);
44  n_private.param("euclidean_distance", euclidean_distance, 0.25);
45  n_private.param("pub_markers", p_marker_pub, false);
46 
47  pub_tracks_box_kf = n.advertise<datmo::TrackArray>("datmo/box_kf", 10);
48  pub_marker_array = n.advertise<visualization_msgs::MarkerArray>("datmo/marker_array", 10);
49  sub_scan = n.subscribe("/scan", 1, &Datmo::callback, this);
50 
51 }
52 
54 }
55 void Datmo::callback(const sensor_msgs::LaserScan::ConstPtr& scan_in){
56 
57  // delete all Markers
58  visualization_msgs::Marker marker;
59  visualization_msgs::MarkerArray markera;
60  marker.action =3;
61  markera.markers.push_back(marker);
62  pub_marker_array.publish(markera);
63 
64  // Only if there is a transform between the world and lidar frame continue
66 
67  //Find position of ego vehicle in world frame, so it can be fed through to the cluster objects
68  tf::StampedTransform ego_pose;
70 
71  //TODO implement varying calculation of dt
72  dt = 0.08;
73 
74  if (time > ros::Time::now()){clusters.clear();}
75  time = ros::Time::now();
76  auto start = chrono::steady_clock::now();
77 
78  vector<pointList> point_clusters_not_transformed;
79  Datmo::Clustering(scan_in, point_clusters_not_transformed);
80 
81  //Transform Clusters to world_frame
82  vector<pointList> point_clusters;
83  for (unsigned int i = 0; i < point_clusters_not_transformed.size(); ++i) {
84  pointList point_cluster;
85  transformPointList(point_clusters_not_transformed[i], point_cluster);
86  point_clusters.push_back(point_cluster);
87  }
88 
89 
90  // Cluster Association based on the Euclidean distance
91  // I should check first all the distances and then associate based on the closest distance
92 
93  vector<bool> g_matched(point_clusters.size(),false); // The Group has been matched with a Cluster
94  vector<bool> c_matched(clusters.size(),false); // The Cluster object has been matched with a group
95 
96  double euclidean[point_clusters.size()][clusters.size()]; // Matrix object to save the euclidean distances
97 
98  //Finding mean coordinates of group and associating with cluster Objects
99  double mean_x = 0, mean_y = 0;
100 
101  for(unsigned int g = 0; g<point_clusters.size();++g){
102  double sum_x = 0, sum_y = 0;
103 
104  for(unsigned int l =0; l<point_clusters[g].size(); l++){
105  sum_x = sum_x + point_clusters[g][l].first;
106  sum_y = sum_y + point_clusters[g][l].second;
107  }
108  mean_x = sum_x / point_clusters[g].size();
109  mean_y = sum_y / point_clusters[g].size();
110 
111  for(unsigned int c=0;c<clusters.size();++c){
112  euclidean[g][c] = abs( mean_x - clusters[c].meanX()) + abs(mean_y - clusters[c].meanY());
113  }
114  }
115 
116  //Find the smallest euclidean distance and associate if smaller than the threshold
117  vector<pair <int,int>> pairs;
118  for(unsigned int c=0; c<clusters.size();++c){
119  unsigned int position;
120  double min_distance = euclidean_distance;
121  for(unsigned int g=0; g<point_clusters.size();++g){
122  if(euclidean[g][c] < min_distance){
123  min_distance = euclidean[g][c];
124  position = g;
125  }
126  }
127  if(min_distance < euclidean_distance){
128  g_matched[position] = true, c_matched[c] = true;
129  pairs.push_back(pair<int,int>(c,position));
130  }
131  }
132 
133  //Update Tracked Clusters
134  #pragma omp parallel for
135  for(unsigned int p=0; p<pairs.size();++p){
136  clusters[pairs[p].first].update(point_clusters[pairs[p].second], dt, ego_pose);
137  }
138 
139  //Delete Not Associated Clusters
140  unsigned int o=0;
141  unsigned int p = clusters.size();
142  while(o<p){
143  if(c_matched[o] == false){
144 
145  std::swap(clusters[o], clusters.back());
146  clusters.pop_back();
147 
148  std::swap(c_matched[o], c_matched.back());
149  c_matched.pop_back();
150 
151  o--;
152  p--;
153  }
154  o++;
155  }
156 
157  // Initialisation of new Cluster Objects
158  for(unsigned int i=0; i<point_clusters.size();++i){
159  if(g_matched[i] == false && point_clusters[i].size()< max_cluster_size){
160  Cluster cl(cclusters, point_clusters[i], dt, world_frame, ego_pose);
161  cclusters++;
162  clusters.push_back(cl);
163  }
164  }
165 
166  //Visualizations and msg publications
167  visualization_msgs::MarkerArray marker_array;
168  datmo::TrackArray track_array_box_kf;
169  for (unsigned int i =0; i<clusters.size();i++){
170 
171  track_array_box_kf.tracks.push_back(clusters[i].msg_track_box_kf);
172 
173  if (p_marker_pub){
174  marker_array.markers.push_back(clusters[i].getClosestCornerPointVisualisationMessage());
175  marker_array.markers.push_back(clusters[i].getBoundingBoxCenterVisualisationMessage());
176  marker_array.markers.push_back(clusters[i].getArrowVisualisationMessage());
177  marker_array.markers.push_back(clusters[i].getThetaL1VisualisationMessage());
178  marker_array.markers.push_back(clusters[i].getThetaL2VisualisationMessage());
179  marker_array.markers.push_back(clusters[i].getThetaBoxVisualisationMessage());
180  marker_array.markers.push_back(clusters[i].getClusterVisualisationMessage());
181  marker_array.markers.push_back(clusters[i].getBoundingBoxVisualisationMessage());
182  marker_array.markers.push_back(clusters[i].getBoxModelKFVisualisationMessage());
183  marker_array.markers.push_back(clusters[i].getLShapeVisualisationMessage());
184  marker_array.markers.push_back(clusters[i].getLineVisualisationMessage());
185  marker_array.markers.push_back(clusters[i].getBoxSolidVisualisationMessage());
186  };
187  }
188 
189  pub_marker_array.publish(marker_array);
190  pub_tracks_box_kf.publish(track_array_box_kf);
191  visualiseGroupedPoints(point_clusters);
192 
193  }
194  else{ //If the tf is not possible init all states at 0
195  ROS_WARN_DELAYED_THROTTLE(1 ,"No transform could be found between %s and %s", lidar_frame.c_str(), world_frame.c_str());
196  };
197 }
198 void Datmo::visualiseGroupedPoints(const vector<pointList>& point_clusters){
199  //Publishing the clusters with different colors
200  visualization_msgs::MarkerArray marker_array;
201  //Populate grouped points message
202  visualization_msgs::Marker gpoints;
203  gpoints.header.frame_id = world_frame;
204  gpoints.header.stamp = ros::Time::now();
205  gpoints.ns = "clustered_points";
206  gpoints.action = visualization_msgs::Marker::ADD;
207  gpoints.pose.orientation.w = 1.0;
208  gpoints.type = visualization_msgs::Marker::POINTS;
209  // POINTS markers use x and y scale for width/height respectively
210  gpoints.scale.x = 0.04;
211  gpoints.scale.y = 0.04;
212  for(unsigned int i=0; i<point_clusters.size(); ++i){
213 
214  gpoints.id = cg;
215  cg++;
216  gpoints.color.g = rand() / double(RAND_MAX);
217  gpoints.color.b = rand() / double(RAND_MAX);
218  gpoints.color.r = rand() / double(RAND_MAX);
219  gpoints.color.a = 1.0;
220  //gpoints.lifetime = ros::Duration(0.08);
221  for(unsigned int j=0; j<point_clusters[i].size(); ++j){
223  p.x = point_clusters[i][j].first;
224  p.y = point_clusters[i][j].second;
225  p.z = 0;
226  gpoints.points.push_back(p);
227  }
228  marker_array.markers.push_back(gpoints);
229  gpoints.points.clear();
230  }
231  pub_marker_array.publish(marker_array);
232 
233 }
234 void Datmo::Clustering(const sensor_msgs::LaserScan::ConstPtr& scan_in, vector<pointList> &clusters){
235  scan = *scan_in;
236 
237 
238  int cpoints = 0;
239 
240  //Find the number of non inf laser scan values and save them in c_points
241  for (unsigned int i = 0; i < scan.ranges.size(); ++i){
242  if(isinf(scan.ranges[i]) == 0){
243  cpoints++;
244  }
245  }
246  const int c_points = cpoints;
247 
248  int j = 0;
249  vector< vector<float> > polar(c_points +1 ,vector<float>(2)); //c_points+1 for wrapping
250  for(unsigned int i = 0; i<scan.ranges.size(); ++i){
251  if(!isinf(scan.ranges[i])){
252  polar[j][0] = scan.ranges[i]; //first column is the range
253  polar[j][1] = scan.angle_min + i*scan.angle_increment; //second angle in rad
254  j++;
255  }
256  }
257 
258  //Complete the circle
259  polar[c_points] = polar[0];
260 
261  //Find clusters based on adaptive threshold distance
262  float d;
263 
264  //There are two flags, since two consecutive points can belong to two independent clusters
265  vector<bool> clustered1(c_points+1 ,false); //change to true when it is the first of the cluster
266  vector<bool> clustered2(c_points+1 ,false); // change to true when it is clustered by another one
267 
268  float l = 45; // λ is an acceptable angle for determining the points to be of the same cluster
269  l = l * 0.0174532; // degree to radian conversion;
270  const float s = 0; // σr is the standard deviation of the noise of the distance measure
271  for (unsigned int i=0; i < c_points ; ++i){
272  double dtheta = polar[i+1][1]- polar[i][1];
273  double adaptive = min(polar[i][0],polar[i+1][0]) * (sin(dth)) / (sin(l - (dth))) + s; //Dthreshold
274  d = sqrt( pow(polar[i][0],2) + pow(polar[i+1][0],2)-2 * polar[i][0]*polar[i+1][0]*cos(polar[i+1][1] - polar[i][1]));
275  //ROS_INFO_STREAM("distance: "<<dth<<", adapt: "<<adaptive<<", dtheta: "<<dtheta);
276  //if(polar[i+1][1]- polar[i][1]<0){
277  //ROS_INFO_STREAM("problem");
278  //}
279 
280  if(d<dth) {
281  clustered1[i] = true; //both points belong to clusters
282  clustered2[i+1] = true;}
283  }
284 
285  clustered2[0] = clustered2[c_points];
286 
287  //Going through the points and finding the beginning of clusters and number of points
288  vector<int> begin; //saving the first index of a cluster
289  vector<int> nclus; //number of clustered points
290  int i =0;
291  bool flag = true; // flag for not going back through the stack
292 
293  while(i<c_points && flag==true){
294 
295  if (clustered1[i] == true && clustered2[i] == false && flag == true){
296  begin.push_back(i);
297  nclus.push_back(1);
298  while(clustered2[i+1] == true && clustered1[i+1] == true ){
299  i++;
300  ++nclus.back();
301  if(i==c_points-1 && flag == true){
302  i = -1;
303  flag = false;
304  }
305  }
306  ++nclus.back();//take care of 0 1 flags - last of the cluster
307  }
308  i++;
309  }
310  // take care of last point being beginning of cluster
311  if(clustered1[cpoints-1]== true and clustered2[c_points-1] == false){
312  begin.push_back(cpoints-1);
313  nclus.push_back(1);
314  i = 0;
315  while(clustered2[i] == true && clustered1[i] == true ){
316  i++;
317  ++nclus.back();
318  }
319 
320  }
321 
322  polar.pop_back(); //remove the wrapping element
323  int len = polar.size();
324 
325  for(unsigned int i=0; i<begin.size(); ++i){
326 
327  pointList cluster;
328 
329  double x,y;
330  int j =begin[i];
331  bool fl = true; // flag for not going back through the stack
332 
333  while (j<nclus[i]+begin[i]){
334  if(j== len && fl == true) fl = false;
335  if (fl == true)
336  {
337  x = polar[j][0] * cos(polar[j][1]); //x = r × cos( θ )
338  y = polar[j][0] * sin(polar[j][1]); //y = r × sin( θ )
339  }
340  else{
341  x = polar[j-len][0] *cos(polar[j-len][1]); //x = r × cos( θ )
342  y = polar[j-len][0] *sin(polar[j-len][1]); //y = r × sin( θ )
343  }
344  cluster.push_back(Point(x, y));
345  ++j;
346  }
347  clusters.push_back(cluster);
348  }
349 }
351  //This funcion transforms pointlist between coordinate frames and it is a wrapper for the
352  //transformPoint function
353  //There is not try catch block because it is supposed to be already encompassed into one
354 
355  geometry_msgs::PointStamped point_in, point_out;
356  Point point;
357  point_in.header.frame_id = lidar_frame;
358  point_in.header.stamp = ros::Time(0);
359  for (unsigned int i = 0; i < in.size(); ++i) {
360  point_in.point.x = in[i].first;
361  point_in.point.y = in[i].second;
362  tf_listener.transformPoint(world_frame, point_in , point_out);
363  point.first = point_out.point.x;
364  point.second= point_out.point.y;
365  out.push_back(point);
366  }
367 }
d
ros::Publisher pub_marker_array
Definition: datmo.hpp:75
#define ROS_WARN_DELAYED_THROTTLE(period,...)
unsigned long int cg
Definition: datmo.hpp:86
bool canTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, std::string *error_msg=NULL) const
ROSCPP_DECL void start()
tf::TransformListener tf_listener
Definition: datmo.hpp:73
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
int max_cluster_size
Definition: datmo.hpp:92
double dth
Definition: datmo.hpp:90
XmlRpcServer s
std::pair< double, double > Point
Definition: cluster.hpp:45
void transformPoint(const std::string &target_frame, const geometry_msgs::PointStamped &stamped_in, geometry_msgs::PointStamped &stamped_out) const
void transformPointList(const pointList &, pointList &)
Definition: datmo.cpp:350
vector< Cluster > clusters
Definition: datmo.hpp:79
tf::Vector3 Point
bool p_marker_pub
Definition: datmo.hpp:93
sensor_msgs::LaserScan scan
Definition: datmo.hpp:78
bool param(const std::string &param_name, T &param_val, const T &default_val) const
string world_frame
Definition: datmo.hpp:96
void publish(const boost::shared_ptr< M > &message) const
string lidar_frame
Definition: datmo.hpp:95
std::vector< Point > pointList
Definition: cluster.hpp:46
void Clustering(const sensor_msgs::LaserScan::ConstPtr &, vector< pointList > &)
Definition: datmo.cpp:234
ros::Publisher pub_tracks_box_kf
Definition: datmo.hpp:76
#define ROS_INFO(...)
void visualiseGroupedPoints(const vector< pointList > &)
Definition: datmo.cpp:198
double euclidean_distance
Definition: datmo.hpp:91
double min(double a, double b)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
double dt
Definition: datmo.hpp:82
ros::Subscriber sub_scan
Definition: datmo.hpp:77
ros::Time time
Definition: datmo.hpp:83
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
INLINE Rall1d< T, V, S > abs(const Rall1d< T, V, S > &x)
void lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, StampedTransform &transform) const
void callback(const sensor_msgs::LaserScan::ConstPtr &)
Definition: datmo.cpp:55
static Time now()
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
unsigned long int cclusters
Definition: datmo.hpp:87
Datmo()
Definition: datmo.cpp:34
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
~Datmo()
Definition: datmo.cpp:53


datmo
Author(s): Kostas Konstantinidis
autogenerated on Tue May 2 2023 02:58:06