00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00040 #include <occupancy_grid_utils/ray_tracer.h>
00041 #include <laser_geometry/laser_geometry.h>
00042 #include <tf/transform_listener.h>
00043 #include <ros/ros.h>
00044 #include <boost/circular_buffer.hpp>
00045 #include <boost/optional.hpp>
00046 #include <boost/foreach.hpp>
00047
00048 namespace grid_construction_node
00049 {
00050
00051 namespace gm=geometry_msgs;
00052 namespace sm=sensor_msgs;
00053 namespace nm=nav_msgs;
00054 namespace gu=occupancy_grid_utils;
00055
00056 using std::vector;
00057 using std::string;
00058
00059 typedef boost::mutex::scoped_lock Lock;
00060 typedef boost::shared_ptr<gu::LocalizedCloud> CloudPtr;
00061 typedef boost::shared_ptr<gu::LocalizedCloud const> CloudConstPtr;
00062 typedef boost::circular_buffer<CloudConstPtr> CloudBuffer;
00063
00064 class GridConstructionNode
00065 {
00066 public:
00067 GridConstructionNode ();
00068
00069 private:
00070
00071 void scanCallback (const sm::LaserScan& scan);
00072 void buildGrid (const ros::WallTimerEvent& e);
00073
00074
00075
00076
00077
00078 ros::NodeHandle nh_;
00079 const unsigned history_length_;
00080 const double resolution_;
00081 const string fixed_frame_;
00082 const string sensor_frame_;
00083 const double grid_construction_interval_;
00084 const double local_grid_size_;
00085
00086
00087
00088
00089
00090 tf::TransformListener tf_;
00091 ros::Subscriber scan_sub_;
00092 ros::Publisher grid_pub_;
00093 ros::WallTimer build_grid_timer_;
00094 boost::mutex mutex_;
00095
00096
00097
00098
00099
00100 CloudBuffer clouds_;
00101 CloudConstPtr last_cloud_;
00102
00103 };
00104
00105
00106 template <class T>
00107 T getPrivateParam(const string& name, const T& default_value)
00108 {
00109 ros::NodeHandle nh("~");
00110 T value;
00111 nh.param(name, value, default_value);
00112 return value;
00113 }
00114
00115
00116 GridConstructionNode::GridConstructionNode () :
00117 history_length_(getPrivateParam("history_length", 100)), resolution_(getPrivateParam("resolution", 0.1)),
00118 fixed_frame_("map"), sensor_frame_("base_laser_link"),
00119 grid_construction_interval_(getPrivateParam("grid_construction_interval", 0.3)),
00120 local_grid_size_(getPrivateParam("local_grid_size", 15.0)),
00121 scan_sub_(nh_.subscribe("base_scan", 1, &GridConstructionNode::scanCallback, this)),
00122 grid_pub_(nh_.advertise<nm::OccupancyGrid>("local_grid", 1)),
00123 build_grid_timer_(nh_.createWallTimer(ros::WallDuration(grid_construction_interval_),
00124 &GridConstructionNode::buildGrid, this)),
00125 clouds_(history_length_)
00126 {
00127 }
00128
00129
00130 void GridConstructionNode::scanCallback (const sm::LaserScan& scan)
00131 {
00132 try {
00133
00134
00135 if (!tf_.waitForTransform(fixed_frame_, sensor_frame_, scan.header.stamp, ros::Duration(1.0)))
00136 {
00137 ROS_WARN_STREAM ("Timed out waiting for transform from " << sensor_frame_ << " to "
00138 << fixed_frame_ << " at " << scan.header.stamp.toSec());
00139 return;
00140 }
00141
00142
00143 tf::Pose identity(tf::createIdentityQuaternion(), btVector3(0, 0, 0));
00144 tf::Stamped<tf::Pose> odom_pose;
00145 tf_.transformPose(fixed_frame_, tf::Stamped<tf::Pose> (identity, ros::Time(), sensor_frame_), odom_pose);
00146
00147
00148 sm::PointCloud fixed_frame_cloud;
00149 laser_geometry::LaserProjection projector_;
00150 projector_.transformLaserScanToPointCloud (fixed_frame_, scan, fixed_frame_cloud, tf_);
00151
00152
00153 sm::PointCloud sensor_frame_cloud;
00154 tf_.transformPointCloud (sensor_frame_, scan.header.stamp, fixed_frame_cloud, fixed_frame_,
00155 sensor_frame_cloud);
00156
00157
00158 CloudPtr loc_cloud(new gu::LocalizedCloud());
00159 loc_cloud->cloud.points = sensor_frame_cloud.points;
00160 tf::poseTFToMsg(odom_pose, loc_cloud->sensor_pose);
00161 loc_cloud->header.frame_id = fixed_frame_;
00162 Lock lock(mutex_);
00163 last_cloud_=loc_cloud;
00164 }
00165 catch (tf::TransformException& e) {
00166 ROS_INFO ("Not saving scan due to tf lookup exception: %s",
00167 e.what());
00168 }
00169 }
00170
00171
00172 void GridConstructionNode::buildGrid (const ros::WallTimerEvent& scan)
00173 {
00174 if (last_cloud_) {
00175 {
00176 Lock lock(mutex_);
00177 clouds_.push_back(last_cloud_);
00178 last_cloud_.reset();
00179 }
00180
00181 ROS_DEBUG_NAMED ("build_grid", "Building grid with %zu scans", clouds_.size());
00182
00183
00184 gm::PoseStamped identity, odom_pose;
00185 identity.pose.orientation = tf::createQuaternionMsgFromYaw(0);
00186 identity.header.frame_id = sensor_frame_;
00187 identity.header.stamp = ros::Time();
00188 tf_.transformPose(fixed_frame_, identity, odom_pose);
00189
00190
00191 nm::MapMetaData info;
00192 info.origin.position.x = odom_pose.pose.position.x-local_grid_size_/2;
00193 info.origin.position.y = odom_pose.pose.position.y-local_grid_size_/2;
00194 info.origin.orientation = tf::createQuaternionMsgFromYaw(0);
00195 info.resolution = resolution_;
00196 info.width = local_grid_size_/resolution_;
00197 info.height = local_grid_size_/resolution_;
00198
00199 nm::OccupancyGrid fake_grid;
00200 fake_grid.info = info;
00201 gu::OverlayClouds overlay = gu::createCloudOverlay(fake_grid, fixed_frame_, 0.1, 10, 2);
00202 vector<CloudConstPtr> clouds(clouds_.begin(), clouds_.end());
00203 BOOST_FOREACH (CloudConstPtr cloud, clouds_)
00204 gu::addCloud(&overlay, cloud);
00205 nm::OccupancyGrid::ConstPtr grid = gu::getGrid(overlay);
00206
00207 ROS_DEBUG_NAMED ("build_grid", "Done building grid");
00208
00209 grid_pub_.publish(grid);
00210 }
00211 }
00212
00213 }
00214
00215 int main (int argc, char** argv)
00216 {
00217 ros::init(argc, argv, "grid_construction_node");
00218 grid_construction_node::GridConstructionNode node;
00219 ros::spin();
00220 return 0;
00221 }