MapModel.cpp
Go to the documentation of this file.
1 // SVN $HeadURL$
2 // SVN $Id$
3 
4 /*
5  * 6D localization for humanoid robots
6  *
7  * Copyright 2009-2012 Armin Hornung, University of Freiburg
8  * http://www.ros.org/wiki/humanoid_localization
9  *
10  *
11  * This program is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation, version 3.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
25 
26 namespace humanoid_localization{
28 : m_motionMeanZ(0.0),
29  m_motionRangeZ(-1.0), m_motionRangeRoll(-1.0), m_motionRangePitch(-1.0),
30  m_motionObstacleDist(0.2)
31 {
32 
33  // motion model max ranges (particles have to stay within range)
34  nh->param("motion_mean_z", m_motionMeanZ, m_motionMeanZ);
35  nh->param("motion_range_z", m_motionRangeZ, m_motionRangeZ);
36  nh->param("motion_range_roll", m_motionRangeRoll, m_motionRangeRoll);
37  nh->param("motion_range_pitch", m_motionRangePitch, m_motionRangePitch);
38  // this is not correctly used at the moment:
39  //nh->param("motion_occupied_radius", m_motionObstacleDist, m_motionObstacleDist);
40 
41 }
42 
44 
45 }
46 
47 
49  return m_map;
50 }
51 
53  double minX, minY, minZ, maxX, maxY, maxZ;
54  m_map->getMetricMin(minX, minY, minZ);
55  m_map->getMetricMax(maxX, maxY, maxZ);
56 
57  // find min. particle weight:
58  double minWeight = std::numeric_limits<double>::max();
59  for (Particles::iterator it = particles.begin(); it != particles.end(); ++it) {
60  if (it->weight < minWeight)
61  minWeight = it->weight;
62 
63  }
64 
65  minWeight -= 200;
66 
67  unsigned numWall = 0;
68  unsigned numOut = 0;
69  unsigned numMotion = 0;
70 
71 
72  // TODO possible speedup: cluster particles by grid voxels first?
73  // iterate over samples, multi-threaded:
74 #pragma omp parallel for
75  for (unsigned i = 0; i < particles.size(); ++i){
76 
77  octomap::point3d position(particles[i].pose.getOrigin().getX(),
78  particles[i].pose.getOrigin().getY(),
79  particles[i].pose.getOrigin().getZ());
80 
81  // see if outside of map bounds:
82  if (position(0) < minX || position(0) > maxX
83  || position(1) < minY || position(1) > maxY
84  || position(2) < minZ || position(2) > maxZ)
85  {
86  particles[i].weight = minWeight;
87 #pragma omp atomic
88  numOut++;
89  } else {
90 
91  // see if occupied cell:
92  if (this->isOccupied(position)){
93  particles[i].weight = minWeight;
94 #pragma omp atomic
95  numWall++;
96  } else {
97  // see if current pose is has a valid walking height:
98  if (m_motionRangeZ >= 0.0 &&
99  (std::abs(particles[i].pose.getOrigin().getZ() - getFloorHeight(particles[i].pose) - m_motionMeanZ)
100  > m_motionRangeZ))
101  {
102  particles[i].weight = minWeight;
103 #pragma omp atomic
104  numMotion++;
105  } else if (m_motionRangePitch >= 0.0 || m_motionRangeRoll >= 0.0){
106 
107  double yaw, pitch, roll;
108  particles[i].pose.getBasis().getRPY(roll, pitch, yaw);
109 
110  if ((m_motionRangePitch >= 0.0 && std::abs(pitch) > m_motionRangePitch)
111  || (m_motionRangeRoll >= 0.0 && std::abs(roll) > m_motionRangeRoll))
112  {
113  particles[i].weight = minWeight;
114 #pragma omp atomic
115  numMotion++;
116  }
117  }
118  }
119  }
120  } // end loop over particles
121 
122  if (numWall > 0 || numOut > 0 || numMotion > 0){
123  ROS_INFO("Particle weights minimized: %d out of map, %d in obstacles, %d out of motion range", numOut, numWall, numMotion);
124  }
125 
126  if (numOut + numWall >= particles.size()){
127  ROS_WARN("All particles are out of the valid map area or in obstacles!");
128  }
129 
130 }
131 
132 
133 void MapModel::initGlobal(Particles& particles, double z, double roll, double pitch,
134  const Vector6d& initNoise,
135  UniformGeneratorT& rngUniform, NormalGeneratorT& rngNormal){
136  double sizeX,sizeY,sizeZ, minX, minY, minZ;
137  m_map->getMetricSize(sizeX,sizeY,sizeZ);
138  m_map->getMetricMin(minX, minY, minZ);
139 
140  double weight = 1.0 / particles.size();
141  Particles::iterator it = particles.begin();
142  while (true){
143  if (it == particles.end())
144  break;
145  // obtain a pose hypothesis:
146  double x = minX + sizeX * rngUniform();
147  double y = minY + sizeY * rngUniform();
148  std::vector<double> z_list;
149  getHeightlist(x, y, 0.6,z_list);
150 
151  for (unsigned zIdx = 0; zIdx < z_list.size(); zIdx++){
152  if (it == particles.end())
153  break;
154 
155  // not needed => we already know that z contains valid poses
156  // distance map: used distance from obstacles:
157  //std::abs(node->getLogOdds()) < 0.1){
158  // if (!isOccupied(octomap::point3d(x, y, z[zIdx]))){
159 
160  it->pose.getOrigin().setX(x);
161  it->pose.getOrigin().setY(y);
162  // TODO: sample z, roll, pitch
163  it->pose.getOrigin().setZ(z_list.at(zIdx) + z + rngNormal() * initNoise(2));
164  double yaw = rngUniform() * 2 * M_PI -M_PI;
165  it->pose.setRotation(tf::createQuaternionFromRPY(roll, pitch, yaw));
166  it->weight = weight;
167  it++;
168  }
169  }
170 
171 }
172 
173 void MapModel::getHeightlist(double x, double y, double totalHeight, std::vector<double>& heights){
174  double minX, minY, minZ, maxX, maxY, maxZ;
175  m_map->getMetricMin(minX, minY, minZ);
176  m_map->getMetricMax(maxX, maxY, maxZ);
177 
178  double res = m_map->getResolution();
179 
180  double z = maxZ-res/2.0;
181  double lastZ = z + res;
182 
183  while (z >= minZ){
184  if (isOccupied(octomap::point3d(x, y, z))){
185  if (lastZ - z >= totalHeight + res){
186  heights.push_back(z+ res/2.0);
187  }
188  lastZ = z;
189  }
190 
191  z -= res;
192  }
193 }
194 
195 bool MapModel::isOccupied(const octomap::point3d& position) const{
196  octomap::OcTreeNode* mapNode = m_map->search(position);
197  if (mapNode)
198  return isOccupied(mapNode);
199  else return false;
200 }
201 
202 
204 // Distance Map (Endpoint Model)
206 
208 : MapModel(nh)
209 {
210  ROS_ERROR("Distance map implementation is currently not supported");
211  std::string mapFileName;
212  nh->getParam("map_file_dist", mapFileName);
213 
214 // TODO: use FileIO, try octree<float>
215 // octomap::AbstractOcTree* tree = octomap_msgs::fullMsgDataToMap(resp.map.data);
216 // if (tree){
217 // ROS_INFO("Received tree type %s",tree->getTreeType().c_str());
218 // //octree = dynamic_cast<OcTree*>(tree);
219 // }
220 
221  octomap::OcTree* tree = dynamic_cast<octomap::OcTree*>(octomap::AbstractOcTree::read(mapFileName));
222  if (tree){
223  m_map.reset(tree);
224  }
225 
226  if (!m_map|| m_map->size() <= 1){
227  ROS_ERROR("Distance map file loaded from \"%s\" is erroneous, exiting...", mapFileName.c_str());
228  exit(-1);
229  }
230  double x,y,z;
231  m_map->getMetricSize(x,y,z);
232  ROS_INFO("Distance map initialized with %zd nodes (%.2f x %.2f x %.2f m)", m_map->size(), x,y,z);
233 
234 }
235 
237 
238 }
239 
241  if (std::abs(node->getLogOdds()) < m_map->getResolution())
242  return true;
243  else
244  return false;
245 }
246 
247 double DistanceMap::getFloorHeight(const tf::Transform& pose) const{
248  // TODO:
249  ROS_ERROR("DistanceMap::getFloorHeight not implemented yet!");
250 
251  return 0.0;
252 }
253 
255 // Occupancy Map (Raycasting)
257 
258 
260 : MapModel(nh)
261 {
262  std::string servname = "octomap_binary";
263  ROS_INFO("Requesting the map from %s...", nh->resolveName(servname).c_str());
264  octomap_msgs::GetOctomap::Request req;
265  octomap_msgs::GetOctomap::Response resp;
266  while(nh->ok() && !ros::service::call(servname, req, resp))
267  {
268  ROS_WARN("Request to %s failed; trying again...", nh->resolveName(servname).c_str());
269  usleep(1000000);
270  }
271 
272 
273 // Groovy:
274 #if ROS_VERSION_MINIMUM(1, 9, 0)
275  m_map.reset(dynamic_cast<octomap::OcTree*>(octomap_msgs::binaryMsgToMap(resp.map)));
276 #else // Fuerte:
277  m_map.reset(octomap_msgs::binaryMsgDataToMap(resp.map.data));
278 #endif
279 
280  if (!m_map || m_map->size() <= 1){
281  ROS_ERROR("Occupancy map is erroneous, exiting...");
282  exit(-1);
283  }
284  double x,y,z;
285  m_map->getMetricSize(x,y,z);
286  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());
287 
288  m_map->writeBinary("/tmp/octomap_loc");
289 
290 }
291 
293 
294 }
295 
297  return m_map->isNodeOccupied(node);
298 }
299 
300 
301 double OccupancyMap::getFloorHeight(const tf::Transform& pose)const {
302  octomap::point3d end;
303  if (m_map->castRay(octomap::pointTfToOctomap(pose.getOrigin()), octomap::point3d(0.0, 0.0, -1.0), end, false)){
304  // add resolution/2 so height is above voxel boundary:
305  return end.z()+m_map->getResolution()/2.0;
306  } else {
307  ROS_WARN("getFloorHeight raycast did not succeed, using 0.0");
308  return 0.0;
309  }
310 
311 }
312 
313 }
314 
static tf::Quaternion createQuaternionFromRPY(double roll, double pitch, double yaw)
virtual void verifyPoses(Particles &particles)
Definition: MapModel.cpp:52
MapModel(ros::NodeHandle *nh)
Definition: MapModel.cpp:27
boost::shared_ptr< octomap::OcTree > getMap() const
Definition: MapModel.cpp:48
boost::variate_generator< EngineT &, NormalDistributionT > NormalGeneratorT
standard normal-distributed noise
static AbstractOcTree * read(const std::string &filename)
virtual double getFloorHeight(const tf::Transform &pose) const
Definition: MapModel.cpp:301
std::string resolveName(const std::string &name, bool remap=true) const
bool call(const std::string &service_name, MReq &req, MRes &res)
#define M_PI
TFSIMD_FORCE_INLINE const tfScalar & y() const
#define ROS_WARN(...)
static octomap::point3d pointTfToOctomap(const tf::Point &ptTf)
DistanceMap(ros::NodeHandle *nh)
Definition: MapModel.cpp:207
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
boost::shared_ptr< octomap::OcTree > m_map
Definition: MapModel.h:75
boost::variate_generator< EngineT &, UniformDistributionT > UniformGeneratorT
uniform noise in range [0,1)
static octomap::AbstractOcTree * binaryMsgToMap(const Octomap &msg)
float getLogOdds() const
Eigen::Matrix< double, 6, 1 > Vector6d
TFSIMD_FORCE_INLINE const tfScalar & x() const
virtual bool isOccupied(const octomap::point3d &position) const
Definition: MapModel.cpp:195
virtual void initGlobal(Particles &particles, double z, double roll, double pitch, const Vector6d &initNoise, UniformGeneratorT &rngUniform, NormalGeneratorT &rngNormal)
Definition: MapModel.cpp:133
TFSIMD_FORCE_INLINE Vector3 & getOrigin()
TFSIMD_FORCE_INLINE const tfScalar & z() const
OccupancyMap(ros::NodeHandle *nh)
Definition: MapModel.cpp:259
bool getParam(const std::string &key, std::string &s) const
void getHeightlist(double x, double y, double totalHeight, std::vector< double > &heights)
Definition: MapModel.cpp:173
virtual double getFloorHeight(const tf::Transform &pose) const
Definition: MapModel.cpp:247
virtual double getFloorHeight(const tf::Transform &pose) const =0
bool ok() const
std::vector< Particle > Particles
#define ROS_ERROR(...)
virtual bool isOccupied(octomap::OcTreeNode *node) const
Definition: MapModel.cpp:296
virtual bool isOccupied(octomap::OcTreeNode *node) const
Definition: MapModel.cpp:240


humanoid_localization
Author(s): Armin Hornung, Stefan Osswald, Daniel Maier
autogenerated on Mon Jun 10 2019 13:38:31