609 lines
19 KiB
C++
609 lines
19 KiB
C++
|
/*
|
||
|
* Copyright (C) 2012 Open Source Robotics Foundation
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "gazebo/test/ServerFixture.hh"
|
||
|
#include "gazebo/sensors/sensors.hh"
|
||
|
|
||
|
#define LASER_TOL 1e-4
|
||
|
#define DOUBLE_TOL 1e-6
|
||
|
|
||
|
// vertical range values seem to be less accurate
|
||
|
#define VERTICAL_LASER_TOL 1e-3
|
||
|
|
||
|
using namespace gazebo;
|
||
|
class GPURaySensorTest : public ServerFixture
|
||
|
{
|
||
|
};
|
||
|
|
||
|
void OnNewLaserFrame(int *_scanCounter, float *_scanDest,
|
||
|
const float *_scan,
|
||
|
unsigned int _width, unsigned int _height,
|
||
|
unsigned int _depth,
|
||
|
const std::string &/*_format*/)
|
||
|
{
|
||
|
memcpy(_scanDest, _scan, _width * _height * _depth);
|
||
|
*_scanCounter += 1;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
/// \brief Test GPU ray sensor range values,
|
||
|
/// Adapted from LaserUnitBox test in laser.cc
|
||
|
TEST_F(GPURaySensorTest, LaserUnitBox)
|
||
|
{
|
||
|
// Test GPU ray sensors with 3 boxes in the world.
|
||
|
// First GPU ray sensor at identity orientation, second at 90 degree roll
|
||
|
// First place 2 of 3 boxes within range and verify range values.
|
||
|
// then move all 3 boxes out of range and verify range values
|
||
|
Load("worlds/empty_test.world");
|
||
|
|
||
|
// Make sure the render engine is available.
|
||
|
if (rendering::RenderEngine::Instance()->GetRenderPathType() ==
|
||
|
rendering::RenderEngine::NONE)
|
||
|
{
|
||
|
gzerr << "No rendering engine, unable to run gpu laser test\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
std::string modelName = "gpu_ray_model";
|
||
|
std::string raySensorName = "gpu_ray_sensor";
|
||
|
double hMinAngle = -M_PI/2.0;
|
||
|
double hMaxAngle = M_PI/2.0;
|
||
|
double minRange = 0.1;
|
||
|
double maxRange = 5.0;
|
||
|
double rangeResolution = 0.02;
|
||
|
unsigned int samples = 320;
|
||
|
math::Pose testPose(math::Vector3(0, 0, 0.1),
|
||
|
math::Quaternion(0, 0, 0));
|
||
|
|
||
|
// Spawn another gpu ray sensor at 90 degree roll
|
||
|
std::string modelName2 = "gpu_ray_model_roll";
|
||
|
std::string raySensorName2 = "gpu_ray_sensor_roll";
|
||
|
math::Pose testPose2(math::Vector3(0, 0, 0.1),
|
||
|
math::Quaternion(M_PI/2.0, 0, 0));
|
||
|
|
||
|
SpawnGpuRaySensor(modelName, raySensorName, testPose.pos,
|
||
|
testPose.rot.GetAsEuler(), hMinAngle, hMaxAngle, minRange, maxRange,
|
||
|
rangeResolution, samples);
|
||
|
|
||
|
SpawnGpuRaySensor(modelName2, raySensorName2, testPose2.pos,
|
||
|
testPose2.rot.GetAsEuler(), hMinAngle, hMaxAngle, minRange, maxRange,
|
||
|
rangeResolution, samples);
|
||
|
|
||
|
std::string box01 = "box_01";
|
||
|
std::string box02 = "box_02";
|
||
|
std::string box03 = "box_03";
|
||
|
|
||
|
physics::WorldPtr world = physics::get_world("default");
|
||
|
ASSERT_TRUE(world != NULL);
|
||
|
world->GetPhysicsEngine()->SetGravity(math::Vector3(0, 0, 0));
|
||
|
|
||
|
// box in front of ray sensor 1 and 2
|
||
|
math::Pose box01Pose(math::Vector3(1, 0, 0.5), math::Quaternion(0, 0, 0));
|
||
|
// box on the right of ray sensor 1
|
||
|
math::Pose box02Pose(math::Vector3(0, -1, 0.5), math::Quaternion(0, 0, 0));
|
||
|
// box on the left of the ray sensor 1 but out of range
|
||
|
math::Pose box03Pose(math::Vector3(0, maxRange + 1, 0.5),
|
||
|
math::Quaternion(0, 0, 0));
|
||
|
|
||
|
SpawnBox(box01, math::Vector3(1, 1, 1), box01Pose.pos,
|
||
|
box01Pose.rot.GetAsEuler());
|
||
|
|
||
|
SpawnBox(box02, math::Vector3(1, 1, 1), box02Pose.pos,
|
||
|
box02Pose.rot.GetAsEuler());
|
||
|
|
||
|
SpawnBox(box03, math::Vector3(1, 1, 1), box03Pose.pos,
|
||
|
box03Pose.rot.GetAsEuler());
|
||
|
|
||
|
sensors::SensorPtr sensor = sensors::get_sensor(raySensorName);
|
||
|
sensors::GpuRaySensorPtr raySensor =
|
||
|
std::dynamic_pointer_cast<sensors::GpuRaySensor>(sensor);
|
||
|
|
||
|
sensors::SensorPtr sensor2 = sensors::get_sensor(raySensorName2);
|
||
|
sensors::GpuRaySensorPtr raySensor2 =
|
||
|
std::dynamic_pointer_cast<sensors::GpuRaySensor>(sensor2);
|
||
|
|
||
|
// Make sure the above dynamic cast worked.
|
||
|
EXPECT_TRUE(raySensor != NULL);
|
||
|
EXPECT_TRUE(raySensor2 != NULL);
|
||
|
|
||
|
raySensor->SetActive(true);
|
||
|
raySensor2->SetActive(true);
|
||
|
|
||
|
// Verify ray sensor 1 range readings
|
||
|
// listen to new laser frames
|
||
|
float *scan = new float[raySensor->RayCount()
|
||
|
* raySensor->VerticalRayCount() * 3];
|
||
|
int scanCount = 0;
|
||
|
event::ConnectionPtr c =
|
||
|
raySensor->ConnectNewLaserFrame(
|
||
|
std::bind(&::OnNewLaserFrame, &scanCount, scan,
|
||
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
|
||
|
std::placeholders::_4, std::placeholders::_5));
|
||
|
|
||
|
// wait for a few laser scans
|
||
|
int i = 0;
|
||
|
while (scanCount < 10 && i < 300)
|
||
|
{
|
||
|
common::Time::MSleep(10);
|
||
|
i++;
|
||
|
}
|
||
|
EXPECT_LT(i, 300);
|
||
|
|
||
|
int mid = samples / 2;
|
||
|
double unitBoxSize = 1.0;
|
||
|
double expectedRangeAtMidPoint = box01Pose.pos.x - unitBoxSize/2;
|
||
|
|
||
|
// ray sensor 1 should see box01 and box02
|
||
|
EXPECT_NEAR(raySensor->Range(mid), expectedRangeAtMidPoint, LASER_TOL);
|
||
|
EXPECT_NEAR(raySensor->Range(0), expectedRangeAtMidPoint, LASER_TOL);
|
||
|
|
||
|
EXPECT_DOUBLE_EQ(raySensor->Range(samples-1), GZ_DBL_INF);
|
||
|
|
||
|
// Verify ray sensor 2 range readings
|
||
|
// listen to new laser frames
|
||
|
float *scan2 = new float[raySensor2->RayCount()
|
||
|
* raySensor2->VerticalRayCount() * 3];
|
||
|
int scanCount2 = 0;
|
||
|
event::ConnectionPtr c2 =
|
||
|
raySensor->ConnectNewLaserFrame(
|
||
|
std::bind(&::OnNewLaserFrame, &scanCount2, scan2,
|
||
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
|
||
|
std::placeholders::_4, std::placeholders::_5));
|
||
|
|
||
|
// wait for a few laser scans
|
||
|
i = 0;
|
||
|
scanCount2 = 0;
|
||
|
while (scanCount2 < 10 && i < 300)
|
||
|
{
|
||
|
common::Time::MSleep(10);
|
||
|
i++;
|
||
|
}
|
||
|
EXPECT_LT(i, 300);
|
||
|
|
||
|
// Only box01 should be visible to ray sensor 2
|
||
|
EXPECT_NEAR(raySensor2->Range(mid), expectedRangeAtMidPoint, LASER_TOL);
|
||
|
EXPECT_DOUBLE_EQ(raySensor2->Range(0), GZ_DBL_INF);
|
||
|
EXPECT_DOUBLE_EQ(raySensor->Range(samples-1), GZ_DBL_INF);
|
||
|
|
||
|
// Move all boxes out of range
|
||
|
world->GetModel(box01)->SetWorldPose(
|
||
|
math::Pose(math::Vector3(maxRange + 1, 0, 0), math::Quaternion(0, 0, 0)));
|
||
|
world->GetModel(box02)->SetWorldPose(
|
||
|
math::Pose(math::Vector3(0, -(maxRange + 1), 0),
|
||
|
math::Quaternion(0, 0, 0)));
|
||
|
|
||
|
// wait for a few more laser scans
|
||
|
i = 0;
|
||
|
scanCount = 0;
|
||
|
scanCount2 = 0;
|
||
|
while ((scanCount < 10 ||scanCount2 < 10) && i < 300)
|
||
|
{
|
||
|
common::Time::MSleep(10);
|
||
|
i++;
|
||
|
}
|
||
|
EXPECT_LT(i, 300);
|
||
|
|
||
|
for (int i = 0; i < raySensor->RayCount(); ++i)
|
||
|
EXPECT_DOUBLE_EQ(raySensor->Range(i), GZ_DBL_INF);
|
||
|
|
||
|
for (int i = 0; i < raySensor->RayCount(); ++i)
|
||
|
EXPECT_DOUBLE_EQ(raySensor2->Range(i), GZ_DBL_INF);
|
||
|
|
||
|
raySensor->DisconnectNewLaserFrame(c);
|
||
|
raySensor2->DisconnectNewLaserFrame(c2);
|
||
|
|
||
|
delete [] scan;
|
||
|
delete [] scan2;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
/// \brief Spawn multiple GPU ray sensors with same name.
|
||
|
/// Verify that it doesn't crash.
|
||
|
TEST_F(GPURaySensorTest, NameCollision)
|
||
|
{
|
||
|
// Test GPU ray sensors with 3 boxes in the world.
|
||
|
// First GPU ray sensor at identity orientation, second at 90 degree roll
|
||
|
// First place 2 of 3 boxes within range and verify range values.
|
||
|
// then move all 3 boxes out of range and verify range values
|
||
|
Load("worlds/empty_test.world");
|
||
|
|
||
|
// Make sure the render engine is available.
|
||
|
if (rendering::RenderEngine::Instance()->GetRenderPathType() ==
|
||
|
rendering::RenderEngine::NONE)
|
||
|
{
|
||
|
gzerr << "No rendering engine, unable to run gpu laser test\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
std::string modelName = "gpu_ray_model";
|
||
|
std::string raySensorName = "gpu_ray_sensor";
|
||
|
double hMinAngle = -M_PI/2.0;
|
||
|
double hMaxAngle = M_PI/2.0;
|
||
|
double minRange = 0.1;
|
||
|
double maxRange = 5.0;
|
||
|
double rangeResolution = 0.02;
|
||
|
unsigned int samples = 320;
|
||
|
math::Pose testPose(math::Vector3(0, 0, 0.1),
|
||
|
math::Quaternion(0, 0, 0));
|
||
|
|
||
|
// Spawn another gpu ray sensor at 90 degree roll
|
||
|
std::string modelName2 = "gpu_ray_model_roll";
|
||
|
std::string raySensorName2 = "gpu_ray_sensor";
|
||
|
math::Pose testPose2(math::Vector3(0, 0, 0.1),
|
||
|
math::Quaternion(M_PI/2.0, 0, 0));
|
||
|
|
||
|
SpawnGpuRaySensor(modelName, raySensorName, testPose.pos,
|
||
|
testPose.rot.GetAsEuler(), hMinAngle, hMaxAngle, minRange, maxRange,
|
||
|
rangeResolution, samples);
|
||
|
|
||
|
SpawnGpuRaySensor(modelName2, raySensorName2, testPose2.pos,
|
||
|
testPose2.rot.GetAsEuler(), hMinAngle, hMaxAngle, minRange, maxRange,
|
||
|
rangeResolution, samples);
|
||
|
|
||
|
std::string box01 = "box_01";
|
||
|
std::string box02 = "box_02";
|
||
|
std::string box03 = "box_03";
|
||
|
|
||
|
physics::WorldPtr world = physics::get_world("default");
|
||
|
ASSERT_TRUE(world != NULL);
|
||
|
world->GetPhysicsEngine()->SetGravity(math::Vector3(0, 0, 0));
|
||
|
|
||
|
// box in front of ray sensor 1 and 2
|
||
|
math::Pose box01Pose(math::Vector3(1, 0, 0.5), math::Quaternion(0, 0, 0));
|
||
|
// box on the right of ray sensor 1
|
||
|
math::Pose box02Pose(math::Vector3(0, -1, 0.5), math::Quaternion(0, 0, 0));
|
||
|
// box on the left of the ray sensor 1 but out of range
|
||
|
math::Pose box03Pose(math::Vector3(0, maxRange + 1, 0.5),
|
||
|
math::Quaternion(0, 0, 0));
|
||
|
|
||
|
SpawnBox(box01, math::Vector3(1, 1, 1), box01Pose.pos,
|
||
|
box01Pose.rot.GetAsEuler());
|
||
|
|
||
|
SpawnBox(box02, math::Vector3(1, 1, 1), box02Pose.pos,
|
||
|
box02Pose.rot.GetAsEuler());
|
||
|
|
||
|
SpawnBox(box03, math::Vector3(1, 1, 1), box03Pose.pos,
|
||
|
box03Pose.rot.GetAsEuler());
|
||
|
|
||
|
sensors::SensorPtr sensor = sensors::get_sensor(raySensorName);
|
||
|
sensors::GpuRaySensorPtr raySensor =
|
||
|
std::dynamic_pointer_cast<sensors::GpuRaySensor>(sensor);
|
||
|
|
||
|
sensors::SensorPtr sensor2 = sensors::get_sensor(raySensorName2);
|
||
|
sensors::GpuRaySensorPtr raySensor2 =
|
||
|
std::dynamic_pointer_cast<sensors::GpuRaySensor>(sensor2);
|
||
|
|
||
|
// Make sure the above dynamic cast worked.
|
||
|
EXPECT_TRUE(raySensor != NULL);
|
||
|
EXPECT_TRUE(raySensor2 != NULL);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
/// \brief Test GPU ray sensor interaction with terrain
|
||
|
TEST_F(GPURaySensorTest, Heightmap)
|
||
|
{
|
||
|
Load("worlds/gpu_laser_heightmap.world");
|
||
|
|
||
|
// Make sure the render engine is available.
|
||
|
if (rendering::RenderEngine::Instance()->GetRenderPathType() ==
|
||
|
rendering::RenderEngine::NONE)
|
||
|
{
|
||
|
gzerr << "No rendering engine, unable to run gpu laser test\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get a pointer to the gpu laser sensor
|
||
|
std::string gpuLaserName = "gpu_laser_sensor";
|
||
|
int t = 0;
|
||
|
while (sensors::get_sensor(gpuLaserName) == NULL && t < 100)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
++t;
|
||
|
}
|
||
|
ASSERT_LT(t, 100);
|
||
|
sensors::SensorPtr sensor = sensors::get_sensor(gpuLaserName);
|
||
|
sensors::GpuRaySensorPtr raySensor =
|
||
|
std::dynamic_pointer_cast<sensors::GpuRaySensor>(sensor);
|
||
|
|
||
|
EXPECT_TRUE(raySensor != NULL);
|
||
|
|
||
|
// listen to new laser frames
|
||
|
float *scan = new float[raySensor->RayCount()
|
||
|
* raySensor->VerticalRayCount() * 3];
|
||
|
int scanCount = 0;
|
||
|
event::ConnectionPtr c =
|
||
|
raySensor->ConnectNewLaserFrame(
|
||
|
std::bind(&::OnNewLaserFrame, &scanCount, scan,
|
||
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
|
||
|
std::placeholders::_4, std::placeholders::_5));
|
||
|
|
||
|
// wait for a few laser scans
|
||
|
int i = 0;
|
||
|
while (scanCount < 10 && i < 300)
|
||
|
{
|
||
|
common::Time::MSleep(10);
|
||
|
i++;
|
||
|
}
|
||
|
EXPECT_LT(i, 300);
|
||
|
|
||
|
// Verify initial laser range readings. Nothing should be intersecting
|
||
|
double maxRange = 10;
|
||
|
EXPECT_NEAR(raySensor->RangeMax(), maxRange, LASER_TOL);
|
||
|
|
||
|
for (int i = 0; i < raySensor->RayCount(); ++i)
|
||
|
EXPECT_DOUBLE_EQ(raySensor->Range(i), GZ_DBL_INF);
|
||
|
|
||
|
// Move laser model very close to terrain, it should now returns range values
|
||
|
// that are less than half the max range
|
||
|
std::string gpuLaserModelName = "gpu_laser";
|
||
|
physics::WorldPtr world = physics::get_world("default");
|
||
|
ASSERT_TRUE(world != NULL);
|
||
|
world->GetModel(gpuLaserModelName)->SetWorldPose(
|
||
|
math::Pose(math::Vector3(13.2, 0, 0.035), math::Quaternion(0, 0, 0)));
|
||
|
|
||
|
// wait for a few laser scans
|
||
|
i = 0;
|
||
|
scanCount = 0;
|
||
|
while (scanCount < 10 && i < 300)
|
||
|
{
|
||
|
common::Time::MSleep(10);
|
||
|
i++;
|
||
|
}
|
||
|
EXPECT_LT(i, 300);
|
||
|
|
||
|
for (int i = 0; i < raySensor->RayCount(); ++i)
|
||
|
EXPECT_TRUE(raySensor->Range(i) < maxRange / 2.0);
|
||
|
|
||
|
raySensor->DisconnectNewLaserFrame(c);
|
||
|
|
||
|
delete [] scan;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
/// \brief Test GPU ray sensor vertical component
|
||
|
TEST_F(GPURaySensorTest, LaserVertical)
|
||
|
{
|
||
|
// issue #946
|
||
|
#ifdef __APPLE__
|
||
|
return;
|
||
|
#endif
|
||
|
|
||
|
// Test a ray sensor that has a vertical range component.
|
||
|
// Place a box within range and verify range values,
|
||
|
// then move the box out of range and verify range values
|
||
|
|
||
|
Load("worlds/empty_test.world");
|
||
|
|
||
|
// Make sure the render engine is available.
|
||
|
if (rendering::RenderEngine::Instance()->GetRenderPathType() ==
|
||
|
rendering::RenderEngine::NONE)
|
||
|
{
|
||
|
gzerr << "No rendering engine, unable to run gpu laser test\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
std::string modelName = "gpu_ray_model";
|
||
|
std::string raySensorName = "gpu_ray_sensor";
|
||
|
double hMinAngle = -M_PI/4.0;
|
||
|
double hMaxAngle = M_PI/4.0;
|
||
|
double vMinAngle = -M_PI/4.0;
|
||
|
double vMaxAngle = M_PI/4.0;
|
||
|
double minRange = 0.1;
|
||
|
double maxRange = 5.0;
|
||
|
double rangeResolution = 0.02;
|
||
|
unsigned int samples = 640;
|
||
|
unsigned int vSamples = 25;
|
||
|
double vAngleStep = (vMaxAngle - vMinAngle) / (vSamples-1);
|
||
|
ignition::math::Pose3d testPose(ignition::math::Vector3d(0.25, 0, 0.5),
|
||
|
ignition::math::Quaterniond::Identity);
|
||
|
|
||
|
SpawnGpuRaySensorVertical(modelName, raySensorName, testPose.Pos(),
|
||
|
testPose.Rot().Euler(), hMinAngle, hMaxAngle, vMinAngle, vMaxAngle,
|
||
|
minRange, maxRange, rangeResolution, samples, vSamples, 1, 1);
|
||
|
|
||
|
sensors::SensorPtr sensor = sensors::get_sensor(raySensorName);
|
||
|
sensors::GpuRaySensorPtr raySensor =
|
||
|
std::dynamic_pointer_cast<sensors::GpuRaySensor>(sensor);
|
||
|
|
||
|
EXPECT_TRUE(raySensor != nullptr);
|
||
|
|
||
|
physics::WorldPtr world = physics::get_world("default");
|
||
|
ASSERT_TRUE(world != nullptr);
|
||
|
world->GetPhysicsEngine()->SetGravity(ignition::math::Vector3d::Zero);
|
||
|
|
||
|
std::string box01 = "box_01";
|
||
|
|
||
|
// box in front of ray sensor
|
||
|
ignition::math::Pose3d box01Pose(ignition::math::Vector3d(1, 0, 0.5),
|
||
|
ignition::math::Quaterniond::Identity);
|
||
|
|
||
|
SpawnBox(box01, ignition::math::Vector3d::One, box01Pose.Pos(),
|
||
|
box01Pose.Rot().Euler());
|
||
|
|
||
|
raySensor->SetActive(true);
|
||
|
|
||
|
float *scan = new float[raySensor->RayCount()
|
||
|
* raySensor->VerticalRayCount() * 3];
|
||
|
int scanCount = 0;
|
||
|
event::ConnectionPtr c =
|
||
|
raySensor->ConnectNewLaserFrame(
|
||
|
std::bind(&::OnNewLaserFrame, &scanCount, scan,
|
||
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
|
||
|
std::placeholders::_4, std::placeholders::_5));
|
||
|
|
||
|
// wait for a few laser scans
|
||
|
int iter = 0;
|
||
|
while (scanCount < 10 && iter < 600)
|
||
|
{
|
||
|
common::Time::MSleep(10);
|
||
|
iter++;
|
||
|
}
|
||
|
EXPECT_LT(iter, 600);
|
||
|
|
||
|
unsigned int mid = samples / 2;
|
||
|
double unitBoxSize = 1.0;
|
||
|
|
||
|
double angleStep = vMinAngle;
|
||
|
|
||
|
// all vertical laser planes should sense box
|
||
|
for (unsigned int i = 0; i < vSamples; ++i)
|
||
|
{
|
||
|
double expectedRangeAtMidPoint = box01Pose.Pos().X() - unitBoxSize/2
|
||
|
- testPose.Pos().X();
|
||
|
double expectedRange = expectedRangeAtMidPoint / cos(angleStep);
|
||
|
|
||
|
EXPECT_NEAR(raySensor->Range(i*samples + mid),
|
||
|
expectedRange, VERTICAL_LASER_TOL);
|
||
|
|
||
|
angleStep += vAngleStep;
|
||
|
|
||
|
// EXPECT_DOUBLE_EQ(raySensor->Range(i*samples), GZ_DBL_INF);
|
||
|
// EXPECT_DOUBLE_EQ(raySensor->Range(i*samples + samples-1), GZ_DBL_INF);
|
||
|
}
|
||
|
|
||
|
// Move box out of range
|
||
|
world->GetModel(box01)->SetWorldPose(
|
||
|
ignition::math::Pose3d(ignition::math::Vector3d(maxRange + 1, 0, 0),
|
||
|
ignition::math::Quaterniond::Identity));
|
||
|
|
||
|
// wait for a few more laser scans
|
||
|
iter = 0;
|
||
|
scanCount = 0;
|
||
|
while (scanCount < 10 && iter < 300)
|
||
|
{
|
||
|
common::Time::MSleep(10);
|
||
|
iter++;
|
||
|
}
|
||
|
EXPECT_LT(iter, 300);
|
||
|
|
||
|
for (int j = 0; j < raySensor->VerticalRayCount(); ++j)
|
||
|
{
|
||
|
for (int i = 0; i < raySensor->RayCount(); ++i)
|
||
|
{
|
||
|
EXPECT_DOUBLE_EQ(raySensor->Range(j*raySensor->RayCount() + i),
|
||
|
IGN_DBL_INF);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
raySensor->DisconnectNewLaserFrame(c);
|
||
|
|
||
|
delete [] scan;
|
||
|
}
|
||
|
|
||
|
TEST_F(GPURaySensorTest, LaserScanResolution)
|
||
|
{
|
||
|
// Test gpu ray sensor scan resolution.
|
||
|
// Orient the sensor to face downwards and verify that the interpolated
|
||
|
// range values all intersect with ground plane at z = 0;
|
||
|
Load("worlds/empty.world");
|
||
|
|
||
|
// Make sure the render engine is available.
|
||
|
if (rendering::RenderEngine::Instance()->GetRenderPathType() ==
|
||
|
rendering::RenderEngine::NONE)
|
||
|
{
|
||
|
gzerr << "No rendering engine, unable to run gpu laser test\n";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
std::string modelName = "gpu_ray_model";
|
||
|
std::string raySensorName = "gpu_ray_sensor";
|
||
|
// use asymmetric horizontal angles to make test more difficult
|
||
|
double hMinAngle = -M_PI/4.0;
|
||
|
double hMaxAngle = M_PI/8.0;
|
||
|
double vMinAngle = -0.1;
|
||
|
double vMaxAngle = 0.1;
|
||
|
double vMidAngle = M_PI/2.0;
|
||
|
double minRange = 0.01;
|
||
|
double maxRange = 5.0;
|
||
|
// Test fails with a smaller rangeResolution (it should be 0.03)
|
||
|
double rangeResolution = 0.12;
|
||
|
unsigned int hSamples = 641;
|
||
|
unsigned int vSamples = 5;
|
||
|
double hResolution = 3;
|
||
|
double vResolution = 3;
|
||
|
double hAngleStep = (hMaxAngle - hMinAngle) / (hSamples*hResolution-1);
|
||
|
double vAngleStep = (vMaxAngle - vMinAngle) / (vSamples*vResolution-1);
|
||
|
double z0 = 0.5;
|
||
|
ignition::math::Pose3d testPose(ignition::math::Vector3d(0.25, 0, z0),
|
||
|
ignition::math::Quaterniond(0, vMidAngle, 0));
|
||
|
|
||
|
SpawnGpuRaySensorVertical(modelName, raySensorName, testPose.Pos(),
|
||
|
testPose.Rot().Euler(), hMinAngle, hMaxAngle, vMinAngle, vMaxAngle,
|
||
|
minRange, maxRange, rangeResolution, hSamples, vSamples,
|
||
|
hResolution, vResolution);
|
||
|
|
||
|
sensors::SensorPtr sensor = sensors::get_sensor(raySensorName);
|
||
|
sensors::GpuRaySensorPtr raySensor =
|
||
|
std::dynamic_pointer_cast<sensors::GpuRaySensor>(sensor);
|
||
|
|
||
|
EXPECT_TRUE(raySensor != nullptr);
|
||
|
|
||
|
physics::WorldPtr world = physics::get_world("default");
|
||
|
ASSERT_TRUE(world != nullptr);
|
||
|
|
||
|
raySensor->SetActive(true);
|
||
|
|
||
|
float *scan = new float[raySensor->RangeCount()
|
||
|
* raySensor->VerticalRangeCount() * 3];
|
||
|
int scanCount = 0;
|
||
|
event::ConnectionPtr c =
|
||
|
raySensor->ConnectNewLaserFrame(
|
||
|
std::bind(&::OnNewLaserFrame, &scanCount, scan,
|
||
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
|
||
|
std::placeholders::_4, std::placeholders::_5));
|
||
|
|
||
|
// wait for a few laser scans
|
||
|
int iter = 0;
|
||
|
while (scanCount < 10 && iter < 300)
|
||
|
{
|
||
|
common::Time::MSleep(100);
|
||
|
iter++;
|
||
|
}
|
||
|
EXPECT_LT(iter, 300);
|
||
|
|
||
|
unsigned int h, v;
|
||
|
|
||
|
for (v = 0; v < vSamples * vResolution; ++v)
|
||
|
{
|
||
|
for (h = 0; h < hSamples * hResolution; ++h)
|
||
|
{
|
||
|
// pitch angle
|
||
|
double p = vMinAngle + v*vAngleStep;
|
||
|
// yaw angle
|
||
|
double y = hMinAngle + h*hAngleStep;
|
||
|
double R = raySensor->Range(v*hSamples*hResolution + h);
|
||
|
|
||
|
ignition::math::Quaterniond rot(0.0, -p, y);
|
||
|
ignition::math::Vector3d axis = testPose.Rot() * rot *
|
||
|
ignition::math::Vector3d::UnitX;
|
||
|
ignition::math::Vector3d intersection = (axis * R) + testPose.Pos();
|
||
|
|
||
|
EXPECT_NEAR(intersection.Z(), 0.0, rangeResolution);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
raySensor->DisconnectNewLaserFrame(c);
|
||
|
|
||
|
delete [] scan;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
::testing::InitGoogleTest(&argc, argv);
|
||
|
return RUN_ALL_TESTS();
|
||
|
}
|