123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- /*
- * Copyright (c) 2013, Willow Garage, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the Willow Garage, Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
- /**
- * @author David Lu!!
- * Test harness for StaticMap Layer for Costmap2D
- */
- #include <costmap_2d/costmap_2d.h>
- #include <costmap_2d/layered_costmap.h>
- #include <costmap_2d/obstacle_layer.h>
- #include <costmap_2d/static_layer.h>
- #include <costmap_2d/observation_buffer.h>
- #include <costmap_2d/testing_helper.h>
- #include <set>
- #include <gtest/gtest.h>
- using namespace costmap_2d;
- /**
- * Tests the reset method
- *
- TEST(costmap, testResetForStaticMap){
- // Define a static map with a large object in the center
- std::vector<unsigned char> staticMap;
- for(unsigned int i=0; i<10; i++){
- for(unsigned int j=0; j<10; j++){
- staticMap.push_back(costmap_2d::LETHAL_OBSTACLE);
- }
- }
- // Allocate the cost map, with a inflation to 3 cells all around
- Costmap2D map(10, 10, RESOLUTION, 0.0, 0.0, 3, 3, 3, OBSTACLE_RANGE, MAX_Z, RAYTRACE_RANGE, 25, staticMap, THRESHOLD);
- // Populate the cost map with a wall around the perimeter. Free space should clear out the room.
- pcl::PointCloud<pcl::PointXYZ> cloud;
- cloud.points.resize(40);
- // Left wall
- unsigned int ind = 0;
- for (unsigned int i = 0; i < 10; i++){
- // Left
- cloud.points[ind].x = 0;
- cloud.points[ind].y = i;
- cloud.points[ind].z = MAX_Z;
- ind++;
- // Top
- cloud.points[ind].x = i;
- cloud.points[ind].y = 0;
- cloud.points[ind].z = MAX_Z;
- ind++;
- // Right
- cloud.points[ind].x = 9;
- cloud.points[ind].y = i;
- cloud.points[ind].z = MAX_Z;
- ind++;
- // Bottom
- cloud.points[ind].x = i;
- cloud.points[ind].y = 9;
- cloud.points[ind].z = MAX_Z;
- ind++;
- }
- double wx = 5.0, wy = 5.0;
- geometry_msgs::Point p;
- p.x = wx;
- p.y = wy;
- p.z = MAX_Z;
- Observation obs(p, cloud, OBSTACLE_RANGE, RAYTRACE_RANGE);
- std::vector<Observation> obsBuf;
- obsBuf.push_back(obs);
- // Update the cost map for this observation
- map.updateWorld(wx, wy, obsBuf, obsBuf);
- // Verify that we now have only 36 cells with lethal cost, thus provong that we have correctly cleared
- // free space
- int hitCount = 0;
- for(unsigned int i=0; i < 10; ++i){
- for(unsigned int j=0; j < 10; ++j){
- if(map.getCost(i, j) == costmap_2d::LETHAL_OBSTACLE){
- hitCount++;
- }
- }
- }
- ASSERT_EQ(hitCount, 36);
- // Veriy that we have 64 non-leathal
- hitCount = 0;
- for(unsigned int i=0; i < 10; ++i){
- for(unsigned int j=0; j < 10; ++j){
- if(map.getCost(i, j) != costmap_2d::LETHAL_OBSTACLE)
- hitCount++;
- }
- }
- ASSERT_EQ(hitCount, 64);
- // Now if we reset the cost map, we should have our map go back to being completely occupied
- map.resetMapOutsideWindow(wx, wy, 0.0, 0.0);
- //We should now go back to everything being occupied
- hitCount = 0;
- for(unsigned int i=0; i < 10; ++i){
- for(unsigned int j=0; j < 10; ++j){
- if(map.getCost(i, j) == costmap_2d::LETHAL_OBSTACLE)
- hitCount++;
- }
- }
- ASSERT_EQ(hitCount, 100);
- }
- /** Test for copying a window of a costmap *
- TEST(costmap, testWindowCopy){
- Costmap2D map(GRID_WIDTH, GRID_HEIGHT, RESOLUTION, 0.0, 0.0, ROBOT_RADIUS, ROBOT_RADIUS, ROBOT_RADIUS,
- 10.0, MAX_Z, 10.0, 25, MAP_10_BY_10, THRESHOLD);
- /*
- for(unsigned int i = 0; i < 10; ++i){
- for(unsigned int j = 0; j < 10; ++j){
- printf("%3d ", map.getCost(i, j));
- }
- printf("\n");
- }
- printf("\n");
- *
- Costmap2D windowCopy;
- //first test that if we try to make a window that is too big, things fail
- windowCopy.copyCostmapWindow(map, 2.0, 2.0, 6.0, 12.0);
- ASSERT_EQ(windowCopy.getSizeInCellsX(), (unsigned int)0);
- ASSERT_EQ(windowCopy.getSizeInCellsY(), (unsigned int)0);
- //Next, test that trying to make a map window itself fails
- map.copyCostmapWindow(map, 2.0, 2.0, 6.0, 6.0);
- ASSERT_EQ(map.getSizeInCellsX(), (unsigned int)10);
- ASSERT_EQ(map.getSizeInCellsY(), (unsigned int)10);
- //Next, test that legal input generates the result that we expect
- windowCopy.copyCostmapWindow(map, 2.0, 2.0, 6.0, 6.0);
- ASSERT_EQ(windowCopy.getSizeInCellsX(), (unsigned int)6);
- ASSERT_EQ(windowCopy.getSizeInCellsY(), (unsigned int)6);
- //check that we actually get the windo that we expect
- for(unsigned int i = 0; i < windowCopy.getSizeInCellsX(); ++i){
- for(unsigned int j = 0; j < windowCopy.getSizeInCellsY(); ++j){
- ASSERT_EQ(windowCopy.getCost(i, j), map.getCost(i + 2, j + 2));
- //printf("%3d ", windowCopy.getCost(i, j));
- }
- //printf("\n");
- }
- }
- //test for updating costmaps with static data
- TEST(costmap, testFullyContainedStaticMapUpdate){
- Costmap2D map(5, 5, RESOLUTION, 0.0, 0.0, ROBOT_RADIUS, ROBOT_RADIUS, ROBOT_RADIUS,
- 10.0, MAX_Z, 10.0, 25, MAP_5_BY_5, THRESHOLD);
- Costmap2D static_map(GRID_WIDTH, GRID_HEIGHT, RESOLUTION, 0.0, 0.0, ROBOT_RADIUS, ROBOT_RADIUS, ROBOT_RADIUS,
- 10.0, MAX_Z, 10.0, 25, MAP_10_BY_10, THRESHOLD);
- map.updateStaticMapWindow(0, 0, 10, 10, MAP_10_BY_10);
- for(unsigned int i = 0; i < map.getSizeInCellsX(); ++i){
- for(unsigned int j = 0; j < map.getSizeInCellsY(); ++j){
- ASSERT_EQ(map.getCost(i, j), static_map.getCost(i, j));
- }
- }
- }
- TEST(costmap, testOverlapStaticMapUpdate){
- Costmap2D map(5, 5, RESOLUTION, 0.0, 0.0, ROBOT_RADIUS, ROBOT_RADIUS, ROBOT_RADIUS,
- 10.0, MAX_Z, 10.0, 25, MAP_5_BY_5, THRESHOLD);
- Costmap2D static_map(GRID_WIDTH, GRID_HEIGHT, RESOLUTION, 0.0, 0.0, ROBOT_RADIUS, ROBOT_RADIUS, ROBOT_RADIUS,
- 10.0, MAX_Z, 10.0, 25, MAP_10_BY_10, THRESHOLD);
- map.updateStaticMapWindow(-10, -10, 10, 10, MAP_10_BY_10);
- ASSERT_FLOAT_EQ(map.getOriginX(), -10);
- ASSERT_FLOAT_EQ(map.getOriginX(), -10);
- ASSERT_EQ(map.getSizeInCellsX(), (unsigned int)15);
- ASSERT_EQ(map.getSizeInCellsY(), (unsigned int)15);
- for(unsigned int i = 0; i < 10; ++i){
- for(unsigned int j = 0; j < 10; ++j){
- ASSERT_EQ(map.getCost(i, j), static_map.getCost(i, j));
- }
- }
- std::vector<unsigned char> blank(100);
- //check to make sure that inflation on updates are being done correctly
- map.updateStaticMapWindow(-10, -10, 10, 10, blank);
- for(unsigned int i = 0; i < map.getSizeInCellsX(); ++i){
- for(unsigned int j = 0; j < map.getSizeInCellsY(); ++j){
- ASSERT_EQ(map.getCost(i, j), 0);
- }
- }
- std::vector<unsigned char> fully_contained(25);
- fully_contained[0] = 254;
- fully_contained[4] = 254;
- fully_contained[5] = 254;
- fully_contained[9] = 254;
- Costmap2D small_static_map(5, 5, RESOLUTION, 0.0, 0.0, ROBOT_RADIUS, ROBOT_RADIUS, ROBOT_RADIUS,
- 10.0, MAX_Z, 10.0, 25, fully_contained, THRESHOLD);
- map.updateStaticMapWindow(0, 0, 5, 5, fully_contained);
- ASSERT_FLOAT_EQ(map.getOriginX(), -10);
- ASSERT_FLOAT_EQ(map.getOriginX(), -10);
- ASSERT_EQ(map.getSizeInCellsX(), (unsigned int)15);
- ASSERT_EQ(map.getSizeInCellsY(), (unsigned int)15);
- for(unsigned int j = 0; j < 5; ++j){
- for(unsigned int i = 0; i < 5; ++i){
- ASSERT_EQ(map.getCost(i + 10, j + 10), small_static_map.getCost(i, j));
- }
- }
- }
- TEST(costmap, testStaticMap){
- Costmap2D map(GRID_WIDTH, GRID_HEIGHT, RESOLUTION, 0.0, 0.0, ROBOT_RADIUS, ROBOT_RADIUS, ROBOT_RADIUS,
- 10.0, MAX_Z, 10.0, 25, MAP_10_BY_10, THRESHOLD);
- ASSERT_EQ(map.getSizeInCellsX(), (unsigned int)10);
- ASSERT_EQ(map.getSizeInCellsY(), (unsigned int)10);
- // Verify that obstacles correctly identified from the static map.
- std::vector<unsigned int> occupiedCells;
- for(unsigned int i = 0; i < 10; ++i){
- for(unsigned int j = 0; j < 10; ++j){
- if(map.getCost(i, j) == costmap_2d::LETHAL_OBSTACLE){
- occupiedCells.push_back(map.getIndex(i, j));
- }
- }
- }
- ASSERT_EQ(occupiedCells.size(), (unsigned int)20);
- // Iterate over all id's and verify that they are present according to their
- for(std::vector<unsigned int>::const_iterator it = occupiedCells.begin(); it != occupiedCells.end(); ++it){
- unsigned int ind = *it;
- unsigned int x, y;
- map.indexToCells(ind, x, y);
- ASSERT_EQ(find(occupiedCells, map.getIndex(x, y)), true);
- ASSERT_EQ(MAP_10_BY_10[ind] >= 100, true);
- ASSERT_EQ(map.getCost(x, y) >= 100, true);
- }
- // Block of 200
- ASSERT_EQ(find(occupiedCells, map.getIndex(7, 2)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(8, 2)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(9, 2)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(7, 3)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(8, 3)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(9, 3)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(7, 4)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(8, 4)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(9, 4)), true);
- // Block of 100
- ASSERT_EQ(find(occupiedCells, map.getIndex(4, 3)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(4, 4)), true);
- // Block of 200
- ASSERT_EQ(find(occupiedCells, map.getIndex(3, 7)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(4, 7)), true);
- ASSERT_EQ(find(occupiedCells, map.getIndex(5, 7)), true);
- // Verify Coordinate Transformations, ROW MAJOR ORDER
- ASSERT_EQ(worldToIndex(map, 0.0, 0.0), (unsigned int)0);
- ASSERT_EQ(worldToIndex(map, 0.0, 0.99), (unsigned int)0);
- ASSERT_EQ(worldToIndex(map, 0.0, 1.0), (unsigned int)10);
- ASSERT_EQ(worldToIndex(map, 1.0, 0.99), (unsigned int)1);
- ASSERT_EQ(worldToIndex(map, 9.99, 9.99), (unsigned int)99);
- ASSERT_EQ(worldToIndex(map, 8.2, 3.4), (unsigned int)38);
- // Ensure we hit the middle of the cell for world co-ordinates
- double wx, wy;
- indexToWorld(map, 99, wx, wy);
- ASSERT_EQ(wx, 9.5);
- ASSERT_EQ(wy, 9.5);
- }
- //*/
- int main(int argc, char** argv){
- ros::init(argc, argv, "obstacle_tests");
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
- }
|