00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <humanoid_localization/MapModel.h>
00025
00026 namespace humanoid_localization{
00027 MapModel::MapModel(ros::NodeHandle* nh)
00028 : m_motionMeanZ(0.0),
00029 m_motionRangeZ(-1.0), m_motionRangeRoll(-1.0), m_motionRangePitch(-1.0),
00030 m_motionObstacleDist(0.2)
00031 {
00032
00033
00034 nh->param("motion_mean_z", m_motionMeanZ, m_motionMeanZ);
00035 nh->param("motion_range_z", m_motionRangeZ, m_motionRangeZ);
00036 nh->param("motion_range_roll", m_motionRangeRoll, m_motionRangeRoll);
00037 nh->param("motion_range_pitch", m_motionRangePitch, m_motionRangePitch);
00038
00039
00040
00041 }
00042
00043 MapModel::~MapModel(){
00044
00045 }
00046
00047
00048 boost::shared_ptr<octomap::OcTree> MapModel::getMap() const{
00049 return m_map;
00050 }
00051
00052 void MapModel::verifyPoses(Particles& particles){
00053 double minX, minY, minZ, maxX, maxY, maxZ;
00054 m_map->getMetricMin(minX, minY, minZ);
00055 m_map->getMetricMax(maxX, maxY, maxZ);
00056
00057
00058 double minWeight = std::numeric_limits<double>::max();
00059 for (Particles::iterator it = particles.begin(); it != particles.end(); ++it) {
00060 if (it->weight < minWeight)
00061 minWeight = it->weight;
00062
00063 }
00064
00065 minWeight -= 200;
00066
00067 unsigned numWall = 0;
00068 unsigned numOut = 0;
00069 unsigned numMotion = 0;
00070
00071
00072
00073
00074 #pragma omp parallel for
00075 for (unsigned i = 0; i < particles.size(); ++i){
00076
00077 octomap::point3d position(particles[i].pose.getOrigin().getX(),
00078 particles[i].pose.getOrigin().getY(),
00079 particles[i].pose.getOrigin().getZ());
00080
00081
00082 if (position(0) < minX || position(0) > maxX
00083 || position(1) < minY || position(1) > maxY
00084 || position(2) < minZ || position(2) > maxZ)
00085 {
00086 particles[i].weight = minWeight;
00087 #pragma omp atomic
00088 numOut++;
00089 } else {
00090
00091
00092 if (this->isOccupied(position)){
00093 particles[i].weight = minWeight;
00094 #pragma omp atomic
00095 numWall++;
00096 } else {
00097
00098 if (m_motionRangeZ >= 0.0 &&
00099 (std::abs(particles[i].pose.getOrigin().getZ() - getFloorHeight(particles[i].pose) - m_motionMeanZ)
00100 > m_motionRangeZ))
00101 {
00102 particles[i].weight = minWeight;
00103 #pragma omp atomic
00104 numMotion++;
00105 } else if (m_motionRangePitch >= 0.0 || m_motionRangeRoll >= 0.0){
00106
00107 double yaw, pitch, roll;
00108 particles[i].pose.getBasis().getRPY(roll, pitch, yaw);
00109
00110 if ((m_motionRangePitch >= 0.0 && std::abs(pitch) > m_motionRangePitch)
00111 || (m_motionRangeRoll >= 0.0 && std::abs(roll) > m_motionRangeRoll))
00112 {
00113 particles[i].weight = minWeight;
00114 #pragma omp atomic
00115 numMotion++;
00116 }
00117 }
00118 }
00119 }
00120 }
00121
00122 if (numWall > 0 || numOut > 0 || numMotion > 0){
00123 ROS_INFO("Particle weights minimized: %d out of map, %d in obstacles, %d out of motion range", numOut, numWall, numMotion);
00124 }
00125
00126 if (numOut + numWall >= particles.size()){
00127 ROS_WARN("All particles are out of the valid map area or in obstacles!");
00128 }
00129
00130 }
00131
00132
00133 void MapModel::initGlobal(Particles& particles, double z, double roll, double pitch,
00134 const Vector6d& initNoise,
00135 UniformGeneratorT& rngUniform, NormalGeneratorT& rngNormal){
00136 double sizeX,sizeY,sizeZ, minX, minY, minZ;
00137 m_map->getMetricSize(sizeX,sizeY,sizeZ);
00138 m_map->getMetricMin(minX, minY, minZ);
00139
00140 double weight = 1.0 / particles.size();
00141 Particles::iterator it = particles.begin();
00142 while (true){
00143 if (it == particles.end())
00144 break;
00145
00146 double x = minX + sizeX * rngUniform();
00147 double y = minY + sizeY * rngUniform();
00148 std::vector<double> z_list;
00149 getHeightlist(x, y, 0.6,z_list);
00150
00151 for (unsigned zIdx = 0; zIdx < z_list.size(); zIdx++){
00152 if (it == particles.end())
00153 break;
00154
00155
00156
00157
00158
00159
00160 it->pose.getOrigin().setX(x);
00161 it->pose.getOrigin().setY(y);
00162
00163 it->pose.getOrigin().setZ(z_list.at(zIdx) + z + rngNormal() * initNoise(2));
00164 double yaw = rngUniform() * 2 * M_PI -M_PI;
00165 it->pose.setRotation(tf::createQuaternionFromRPY(roll, pitch, yaw));
00166 it->weight = weight;
00167 it++;
00168 }
00169 }
00170
00171 }
00172
00173 void MapModel::getHeightlist(double x, double y, double totalHeight, std::vector<double>& heights){
00174 double minX, minY, minZ, maxX, maxY, maxZ;
00175 m_map->getMetricMin(minX, minY, minZ);
00176 m_map->getMetricMax(maxX, maxY, maxZ);
00177
00178 double res = m_map->getResolution();
00179
00180 double z = maxZ-res/2.0;
00181 double lastZ = z + res;
00182
00183 while (z >= minZ){
00184 if (isOccupied(octomap::point3d(x, y, z))){
00185 if (lastZ - z >= totalHeight + res){
00186 heights.push_back(z+ res/2.0);
00187 }
00188 lastZ = z;
00189 }
00190
00191 z -= res;
00192 }
00193 }
00194
00195 bool MapModel::isOccupied(const octomap::point3d& position) const{
00196 octomap::OcTreeNode* mapNode = m_map->search(position);
00197 if (mapNode)
00198 return isOccupied(mapNode);
00199 else return false;
00200 }
00201
00202
00204
00206
00207 DistanceMap::DistanceMap(ros::NodeHandle* nh)
00208 : MapModel(nh)
00209 {
00210 ROS_ERROR("Distance map implementation is currently not supported");
00211 std::string mapFileName;
00212 nh->getParam("map_file_dist", mapFileName);
00213
00214
00215
00216
00217
00218
00219
00220
00221 octomap::OcTree* tree = dynamic_cast<octomap::OcTree*>(octomap::AbstractOcTree::read(mapFileName));
00222 if (tree){
00223 m_map.reset(tree);
00224 }
00225
00226 if (!m_map|| m_map->size() <= 1){
00227 ROS_ERROR("Distance map file loaded from \"%s\" is erroneous, exiting...", mapFileName.c_str());
00228 exit(-1);
00229 }
00230 double x,y,z;
00231 m_map->getMetricSize(x,y,z);
00232 ROS_INFO("Distance map initialized with %zd nodes (%.2f x %.2f x %.2f m)", m_map->size(), x,y,z);
00233
00234 }
00235
00236 DistanceMap::~DistanceMap(){
00237
00238 }
00239
00240 bool DistanceMap::isOccupied(octomap::OcTreeNode* node) const{
00241 if (std::abs(node->getLogOdds()) < m_map->getResolution())
00242 return true;
00243 else
00244 return false;
00245 }
00246
00247 double DistanceMap::getFloorHeight(const tf::Transform& pose) const{
00248
00249 ROS_ERROR("DistanceMap::getFloorHeight not implemented yet!");
00250
00251 return 0.0;
00252 }
00253
00255
00257
00258
00259 OccupancyMap::OccupancyMap(ros::NodeHandle* nh)
00260 : MapModel(nh)
00261 {
00262 std::string servname = "octomap_binary";
00263 ROS_INFO("Requesting the map from %s...", nh->resolveName(servname).c_str());
00264 octomap_msgs::GetOctomap::Request req;
00265 octomap_msgs::GetOctomap::Response resp;
00266 while(nh->ok() && !ros::service::call(servname, req, resp))
00267 {
00268 ROS_WARN("Request to %s failed; trying again...", nh->resolveName(servname).c_str());
00269 usleep(1000000);
00270 }
00271
00272
00273
00274 #if ROS_VERSION_MINIMUM(1, 9, 0)
00275 m_map.reset(dynamic_cast<octomap::OcTree*>(octomap_msgs::binaryMsgToMap(resp.map)));
00276 #else // Fuerte:
00277 m_map.reset(octomap_msgs::binaryMsgDataToMap(resp.map.data));
00278 #endif
00279
00280 if (!m_map || m_map->size() <= 1){
00281 ROS_ERROR("Occupancy map is erroneous, exiting...");
00282 exit(-1);
00283 }
00284 double x,y,z;
00285 m_map->getMetricSize(x,y,z);
00286 ROS_INFO("Occupancy map initialized with %zd nodes (%.2f x %.2f x %.2f m), %f m res.", m_map->size(), x,y,z, m_map->getResolution());
00287
00288 m_map->writeBinary("/tmp/octomap_loc");
00289
00290 }
00291
00292 OccupancyMap::~OccupancyMap(){
00293
00294 }
00295
00296 bool OccupancyMap::isOccupied(octomap::OcTreeNode* node) const{
00297 return m_map->isNodeOccupied(node);
00298 }
00299
00300
00301 double OccupancyMap::getFloorHeight(const tf::Transform& pose)const {
00302 octomap::point3d end;
00303 if (m_map->castRay(octomap::pointTfToOctomap(pose.getOrigin()), octomap::point3d(0.0, 0.0, -1.0), end, false)){
00304
00305 return end.z()+m_map->getResolution()/2.0;
00306 } else {
00307 ROS_WARN("getFloorHeight raycast did not succeed, using 0.0");
00308 return 0.0;
00309 }
00310
00311 }
00312
00313 }
00314