/* * 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. * */ #ifdef _WIN32 // Ensure that Winsock2.h is included before Windows.h, which can get // pulled in by anybody (e.g., Boost). #include #endif #include #include #include #include #include "gazebo/gazebo.hh" #include "ServerFixture.hh" using namespace gazebo; ///////////////////////////////////////////////// std::string gazebo::custom_exec(std::string _cmd) { _cmd += " 2>/dev/null"; #ifdef _WIN32 FILE *pipe = _popen(_cmd.c_str(), "r"); #else FILE *pipe = popen(_cmd.c_str(), "r"); #endif if (!pipe) return "ERROR"; char buffer[128]; std::string result = ""; while (!feof(pipe)) { if (fgets(buffer, 128, pipe) != NULL) result += buffer; } #ifdef _WIN32 _pclose(pipe); #else pclose(pipe); #endif return result; } ///////////////////////////////////////////////// void RenderingFixture::SetUp() { // start rendering in test thread rendering::load(); } ///////////////////////////////////////////////// void RenderingFixture::Unload() { rendering::fini(); ServerFixture::Unload(); } ///////////////////////////////////////////////// ServerFixture::ServerFixture() { this->server = NULL; this->serverRunning = false; this->paused = false; this->percentRealTime = 0; this->gotImage = 0; this->imgData = NULL; this->serverThread = NULL; this->uniqueCounter = 0; gzLogInit("test-", "test.log"); gazebo::common::Console::SetQuiet(false); common::SystemPaths::Instance()->AddGazeboPaths( TEST_INTEGRATION_PATH); // Add local search paths boost::filesystem::path path; path = PROJECT_SOURCE_PATH; gazebo::common::SystemPaths::Instance()->AddGazeboPaths(path.string()); path = PROJECT_SOURCE_PATH; path /= "gazebo"; gazebo::common::SystemPaths::Instance()->AddGazeboPaths(path.string()); path = PROJECT_BINARY_PATH; path /= "plugins"; gazebo::common::SystemPaths::Instance()->AddPluginPaths(path.string()); path = PROJECT_BINARY_PATH; path /= "test"; path /= "plugins"; gazebo::common::SystemPaths::Instance()->AddPluginPaths(path.string()); path = TEST_PATH; gazebo::common::SystemPaths::Instance()->AddGazeboPaths(path.string()); } ///////////////////////////////////////////////// ServerFixture::~ServerFixture() { } ///////////////////////////////////////////////// void ServerFixture::TearDown() { this->Unload(); } ///////////////////////////////////////////////// void ServerFixture::Unload() { gzdbg << "ServerFixture::Unload" << std::endl; this->serverRunning = false; if (this->node) this->node->Fini(); if (this->server) { this->server->Stop(); if (this->serverThread) { this->serverThread->join(); } } delete this->serverThread; this->serverThread = NULL; } ///////////////////////////////////////////////// void ServerFixture::Load(const std::string &_worldFilename) { this->Load(_worldFilename, false); } ///////////////////////////////////////////////// void ServerFixture::Load(const std::string &_worldFilename, bool _paused) { std::string s(""); this->Load(_worldFilename, _paused, s); } ///////////////////////////////////////////////// void ServerFixture::Load(const std::string &_worldFilename, bool _paused, const std::string &_physics, const std::vector &_systemPlugins) { std::string params = _worldFilename; if (!_physics.empty()) params += " -e " + _physics; if (_paused) params += " -u"; for (auto plugin : _systemPlugins) params += " -s " + plugin; this->LoadArgs(params); } ///////////////////////////////////////////////// void ServerFixture::LoadArgs(const std::string &_args) { delete this->server; this->server = NULL; // Split the string into a vector of parameters. std::vector params; std::string args = _args; boost::trim_if(args, boost::is_any_of("\t ")); boost::split(params, args, boost::is_any_of("\t "), boost::token_compress_on); bool paused = false; if (std::find(params.begin(), params.end(), "-u") != params.end()) paused = true; // Create, load, and run the server in its own thread this->serverThread = new boost::thread( boost::bind(&ServerFixture::RunServer, this, params)); // Wait for the server to come up // Use a 60 second timeout. int waitCount = 0, maxWaitCount = 6000; while ((!this->server || !this->server->GetInitialized()) && ++waitCount < maxWaitCount) common::Time::MSleep(100); gzdbg << "ServerFixture load in " << static_cast(waitCount)/10.0 << " seconds, timeout after " << static_cast(maxWaitCount)/10.0 << " seconds\n"; if (waitCount >= maxWaitCount) this->launchTimeoutFailure("while waiting for Load() function", waitCount); this->node = transport::NodePtr(new transport::Node()); ASSERT_NO_THROW(this->node->Init()); this->poseSub = this->node->Subscribe("~/pose/local/info", &ServerFixture::OnPose, this, true); this->statsSub = this->node->Subscribe("~/world_stats", &ServerFixture::OnStats, this); this->factoryPub = this->node->Advertise("~/factory"); this->requestPub = this->node->Advertise("~/request"); // Wait for the world to reach the correct pause state. // This might not work properly with multiple worlds. // Use a 30 second timeout. waitCount = 0; maxWaitCount = 3000; while ((!this->server || !this->server->GetInitialized() || !physics::get_world() || physics::get_world()->IsPaused() != paused) && ++waitCount < maxWaitCount) { common::Time::MSleep(100); } ASSERT_LT(waitCount, maxWaitCount); this->factoryPub->WaitForConnection(); this->requestPub->WaitForConnection(); } ///////////////////////////////////////////////// void ServerFixture::RunServer(const std::vector &_args) { // Make room for an extra parameter (gzserver). int argc = _args.size() + 1; char **argv = new char* [argc]; // The first parameter is the name of the program. const char *cmd = "gzserver"; argv[0] = strdup(cmd); // Copy the command line parameters for gzserver. for (size_t i = 0; i < _args.size(); ++i) argv[i + 1] = strdup(_args.at(i).c_str()); ASSERT_NO_THROW(this->server = new Server()); if (!this->server->ParseArgs(argc, argv)) { ASSERT_NO_THROW(delete this->server); this->server = NULL; return; } if (!rendering::get_scene(gazebo::physics::get_world()->GetName())) { ASSERT_NO_THROW(rendering::create_scene( gazebo::physics::get_world()->GetName(), false, true)); } ASSERT_NO_THROW(this->server->Run()); ASSERT_NO_THROW(this->server->Fini()); ASSERT_NO_THROW(delete this->server); this->server = NULL; // Deallocate memory for the command line arguments allocated with strdup. for (int i = 0; i < argc; ++i) free(argv[i]); delete[] argv; } ///////////////////////////////////////////////// rendering::ScenePtr ServerFixture::GetScene( const std::string &_sceneName) { // Wait for the scene to get loaded. int i = 0; int timeoutDS = 20; while (rendering::get_scene(_sceneName) == NULL && i < timeoutDS) { common::Time::MSleep(100); ++i; } if (i >= timeoutDS) { gzerr << "Unable to load the rendering scene.\n" << "Test will fail"; this->launchTimeoutFailure( "while waiting to load rendering scene", i); } return rendering::get_scene(_sceneName); } ///////////////////////////////////////////////// void ServerFixture::OnStats(ConstWorldStatisticsPtr &_msg) { this->simTime = msgs::Convert(_msg->sim_time()); this->realTime = msgs::Convert(_msg->real_time()); this->pauseTime = msgs::Convert(_msg->pause_time()); this->paused = _msg->paused(); if (this->realTime == 0) this->percentRealTime = 0; else this->percentRealTime = (this->simTime / this->realTime).Double(); this->serverRunning = true; } ///////////////////////////////////////////////// void ServerFixture::SetPause(bool _pause) { physics::pause_worlds(_pause); } ///////////////////////////////////////////////// double ServerFixture::GetPercentRealTime() const { while (!this->serverRunning) common::Time::MSleep(100); return this->percentRealTime; } ///////////////////////////////////////////////// void ServerFixture::OnPose(ConstPosesStampedPtr &_msg) { boost::mutex::scoped_lock lock(this->receiveMutex); for (int i = 0; i < _msg->pose_size(); ++i) { this->poses[_msg->pose(i).name()] = msgs::ConvertIgn(_msg->pose(i)); } } ///////////////////////////////////////////////// math::Pose ServerFixture::GetEntityPose(const std::string &_name) { boost::mutex::scoped_lock lock(this->receiveMutex); std::map::iterator iter; iter = this->poses.find(_name); EXPECT_TRUE(iter != this->poses.end()); return iter->second; } ///////////////////////////////////////////////// bool ServerFixture::HasEntity(const std::string &_name) { boost::mutex::scoped_lock lock(this->receiveMutex); std::map::iterator iter; iter = this->poses.find(_name); return iter != this->poses.end(); } ///////////////////////////////////////////////// void ServerFixture::PrintImage(const std::string &_name, unsigned char **_image, unsigned int _width, unsigned int _height, unsigned int _depth) { unsigned int count = _height * _width * _depth; printf("\n"); printf("static unsigned char __%s[] = {", _name.c_str()); unsigned int i; for (i = 0; i < count-1; i++) { if (i % 10 == 0) printf("\n"); else printf(" "); printf("%d,", (*_image)[i]); } printf(" %d};\n", (*_image)[i]); printf("static unsigned char *%s = __%s;\n", _name.c_str(), _name.c_str()); } ///////////////////////////////////////////////// void ServerFixture::PrintScan(const std::string &_name, double *_scan, unsigned int _sampleCount) { printf("static double __%s[] = {\n", _name.c_str()); for (unsigned int i = 0; i < _sampleCount-1; ++i) { if ((i+1) % 5 == 0) printf("%13.10f,\n", math::precision(_scan[i], 10)); else printf("%13.10f, ", math::precision(_scan[i], 10)); } printf("%13.10f};\n", math::precision(_scan[_sampleCount-1], 10)); printf("static double *%s = __%s;\n", _name.c_str(), _name.c_str()); } ///////////////////////////////////////////////// void ServerFixture::FloatCompare(float *_scanA, float *_scanB, unsigned int _sampleCount, float &_diffMax, float &_diffSum, float &_diffAvg) { _diffMax = 0; _diffSum = 0; _diffAvg = 0; for (unsigned int i = 0; i < _sampleCount; ++i) { double diff = fabs(math::precision(_scanA[i], 10) - math::precision(_scanB[i], 10)); _diffSum += diff; if (diff > _diffMax) { _diffMax = diff; } } _diffAvg = _diffSum / _sampleCount; } ///////////////////////////////////////////////// void ServerFixture::DoubleCompare(double *_scanA, double *_scanB, unsigned int _sampleCount, double &_diffMax, double &_diffSum, double &_diffAvg) { _diffMax = 0; _diffSum = 0; _diffAvg = 0; for (unsigned int i = 0; i < _sampleCount; ++i) { double diff; // set diff = 0 if both values are same-sign infinite, as inf - inf = nan if (std::isinf(_scanA[i]) && std::isinf(_scanB[i]) && _scanA[i] * _scanB[i] > 0) { diff = 0; } else { diff = fabs(math::precision(_scanA[i], 10) - math::precision(_scanB[i], 10)); } _diffSum += diff; if (diff > _diffMax) { _diffMax = diff; } } _diffAvg = _diffSum / _sampleCount; } ///////////////////////////////////////////////// void ServerFixture::ImageCompare(unsigned char *_imageA, unsigned char *_imageB, unsigned int _width, unsigned int _height, unsigned int _depth, unsigned int &_diffMax, unsigned int &_diffSum, double &_diffAvg) { _diffMax = 0; _diffSum = 0; for (unsigned int y = 0; y < _height; ++y) { for (unsigned int x = 0; x < _width*_depth; ++x) { int a = _imageA[(y*_width*_depth)+x]; int b = _imageB[(y*_width*_depth)+x]; unsigned int absDiff = abs(a - b); if (absDiff > _diffMax) _diffMax = absDiff; _diffSum += absDiff; } } _diffAvg = _diffSum / (_height*_width*_depth); } ///////////////////////////////////////////////// void ServerFixture::OnNewFrame(const unsigned char *_image, unsigned int _width, unsigned int _height, unsigned int _depth, const std::string &/*_format*/) { memcpy(*this->imgData, _image, _width * _height * _depth); this->gotImage+= 1; } ///////////////////////////////////////////////// void ServerFixture::GetFrame(const std::string &_cameraName, unsigned char **_imgData, unsigned int &_width, unsigned int &_height) { sensors::SensorPtr sensor = sensors::get_sensor(_cameraName); EXPECT_TRUE(sensor != NULL); sensors::CameraSensorPtr camSensor = std::dynamic_pointer_cast(sensor); _width = camSensor->ImageWidth(); _height = camSensor->ImageHeight(); if (*_imgData) { delete *_imgData; *_imgData = NULL; } (*_imgData) = new unsigned char[_width *_height*3]; this->imgData = _imgData; this->gotImage = 0; event::ConnectionPtr c = camSensor->Camera()->ConnectNewImageFrame( boost::bind(&ServerFixture::OnNewFrame, this, _1, _2, _3, _4, _5)); while (this->gotImage < 20) common::Time::MSleep(100); camSensor->Camera()->DisconnectNewImageFrame(c); } ///////////////////////////////////////////////// physics::ModelPtr ServerFixture::SpawnModel(const msgs::Model &_msg) { physics::WorldPtr world = physics::get_world(); ServerFixture::CheckPointer(world); world->InsertModelString( "" + msgs::ModelToSDF(_msg)->ToString("") + ""); common::Time wait(10, 0); common::Time wallStart = common::Time::GetWallTime(); unsigned int waitCount = 0; while (wait > (common::Time::GetWallTime() - wallStart) && !this->HasEntity(_msg.name())) { common::Time::MSleep(10); if (++waitCount % 100 == 0) { gzwarn << "Waiting " << waitCount / 100 << " seconds for " << "box to spawn." << std::endl; } } return world->GetModel(_msg.name()); } ///////////////////////////////////////////////// void ServerFixture::SpawnCamera(const std::string &_modelName, const std::string &_cameraName, const math::Vector3 &_pos, const math::Vector3 &_rpy, unsigned int _width, unsigned int _height, double _rate, const std::string &_noiseType, double _noiseMean, double _noiseStdDev, bool _distortion, double _distortionK1, double _distortionK2, double _distortionK3, double _distortionP1, double _distortionP2, double _cx, double _cy) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "true" << "" << _pos << " " << _rpy << "" << "" << " " << " 1" << " " << _rate << "" << " true" << " " << " 0.78539816339744828" << " " << " " << _width << "" << " " << _height << "" << " R8G8B8" << " " << " " << " 0.1100" << " "; // << " " if (_noiseType.size() > 0) newModelStr << " " << " " << _noiseType << "" << " " << _noiseMean << "" << " " << _noiseStdDev << "" << " "; if (_distortion) newModelStr << " " << " " << _distortionK1 << "" << " " << _distortionK2 << "" << " " << _distortionK3 << "" << " " << _distortionP1 << "" << " " << _distortionP2 << "" << "
" << _cx << " " << _cy << "
" << "
"; newModelStr << "
" << "
" << "" << "
" << "
"; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_modelName, 100, 50); WaitUntilSensorSpawn(_cameraName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::SpawnWideAngleCamera(const std::string &_modelName, const std::string &_cameraName, const ignition::math::Vector3d &_pos, const ignition::math::Vector3d &_rpy, unsigned int _width, unsigned int _height, double _rate, const double _hfov, const std::string &_lensType, const bool _scaleToHfov, const double _cutoffAngle, const double _envTextureSize, const double _c1, const double _c2, const double _f, const std::string &_fun) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "true" << "" << _pos << " " << _rpy << "" << "" << " " << " 1" << " " << _rate << "" << " false" << " " << " " << _hfov << "" << " " << " " << _width << "" << " " << _height << "" << " " << " " << " 0.1100" << " " << " " << " " << _lensType << "" << " " << _scaleToHfov << "" << " " << _cutoffAngle << "" << " " << _envTextureSize << ""; if (_lensType == "custom") { newModelStr << "" << " " << _c1 << "" << " " << _c2 << "" << " " << _f << "" << " " << _fun << "" << " "; } newModelStr << "" << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_modelName, 100, 50); WaitUntilSensorSpawn(_cameraName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::SpawnRaySensor(const std::string &_modelName, const std::string &_raySensorName, const math::Vector3 &_pos, const math::Vector3 &_rpy, double _hMinAngle, double _hMaxAngle, double _vMinAngle, double _vMaxAngle, double _minRange, double _maxRange, double _rangeResolution, unsigned int _samples, unsigned int _vSamples, double _hResolution, double _vResolution, const std::string &_noiseType, double _noiseMean, double _noiseStdDev) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "true" << "" << _pos << " " << _rpy << "" << "" << "" << " 0 0 0.0205 0 0 0" << " " << " " << " 0.021" << " 0.029" << " " << " " << "" << " " << " " << " " << " " << " " << _samples << "" << " " << _hResolution << "" << " " << _hMinAngle << "" << " " << _hMaxAngle << "" << " " << " " << " " << _vSamples << "" << " " << _vResolution << "" << " " << _vMinAngle << "" << " " << _vMaxAngle << "" << " " << " " << " " << " " << _minRange << "" << " " << _maxRange << "" << " " << _rangeResolution <<"" << " "; if (_noiseType.size() > 0) newModelStr << " " << " " << _noiseType << "" << " " << _noiseMean << "" << " " << _noiseStdDev << "" << " "; newModelStr << " " << " true" << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_modelName, 100, 100); WaitUntilSensorSpawn(_raySensorName, 100, 100); } ///////////////////////////////////////////////// sensors::SonarSensorPtr ServerFixture::SpawnSonar(const std::string &_modelName, const std::string &_sonarName, const ignition::math::Pose3d &_pose, const double _minRange, const double _maxRange, const double _radius) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "true" << "" << _pose << "" << "" << " " << " " << " " << _minRange << "" << " " << _maxRange << "" << " " << _radius << "" << " " << " true" << " true" << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_modelName, 100, 100); WaitUntilSensorSpawn(_sonarName, 100, 100); return std::dynamic_pointer_cast( sensors::get_sensor(_sonarName)); } ///////////////////////////////////////////////// void ServerFixture::SpawnGpuRaySensor(const std::string &_modelName, const std::string &_raySensorName, const math::Vector3 &_pos, const math::Vector3 &_rpy, double _hMinAngle, double _hMaxAngle, double _minRange, double _maxRange, double _rangeResolution, unsigned int _samples, const std::string &_noiseType, double _noiseMean, double _noiseStdDev) { this->SpawnGpuRaySensorVertical(_modelName, _raySensorName, _pos.Ign(), _rpy.Ign(), _hMinAngle, _hMaxAngle, 0, 0, _minRange, _maxRange, _rangeResolution, _samples, 1, 1, 1, _noiseType, _noiseMean, _noiseStdDev); } ///////////////////////////////////////////////// void ServerFixture::SpawnGpuRaySensorVertical(const std::string &_modelName, const std::string &_raySensorName, const ignition::math::Vector3d &_pos, const ignition::math::Vector3d &_rpy, double _hMinAngle, double _hMaxAngle, double _vMinAngle, double _vMaxAngle, double _minRange, double _maxRange, double _rangeResolution, unsigned int _samples, unsigned int _vSamples, double _hResolution, double _vResolution, const std::string &_noiseType, double _noiseMean, double _noiseStdDev) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "true" << "" << _pos << " " << _rpy << "" << "" << "" << " 0 0 0.0205 0 0 0" << " " << " " << " 0.021" << " 0.029" << " " << " " << "" << " " << " " << " " << " " << " " << _samples << "" << " " << _hResolution << "" << " " << _hMinAngle << "" << " " << _hMaxAngle << "" << " " << " " << " " << _vSamples << "samples>" << " " << _vResolution << "" << " " << _vMinAngle << "" << " " << _vMaxAngle << "" << " " << " " << " " << " " << _minRange << "" << " " << _maxRange << "" << " " << _rangeResolution <<"" << " "; if (_noiseType.size() > 0) newModelStr << " " << " " << _noiseType << "" << " " << _noiseMean << "" << " " << _noiseStdDev << "" << " "; newModelStr << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_modelName, 100, 100); WaitUntilSensorSpawn(_raySensorName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::SpawnImuSensor(const std::string &_modelName, const std::string &_imuSensorName, const math::Vector3 &_pos, const math::Vector3 &_rpy, const std::string &_noiseType, double _rateNoiseMean, double _rateNoiseStdDev, double _rateBiasMean, double _rateBiasStdDev, double _accelNoiseMean, double _accelNoiseStdDev, double _accelBiasMean, double _accelBiasStdDev) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << std::endl << "true" << std::endl << "" << _pos << " " << _rpy << "" << std::endl << "" << std::endl << "" << std::endl << "0.1" << std::endl << "" << std::endl << "" << std::endl << " 0 0 0.0205 0 0 0" << std::endl << " " << std::endl << " " << std::endl << " 0.021" << std::endl << " 0.029" << std::endl << " " << std::endl << " " << std::endl << "" << std::endl << " " << std::endl << " " << std::endl; if (_noiseType.size() > 0) { newModelStr << "\n" << "\n" << "" << _rateNoiseMean << "\n" << "" << _rateNoiseStdDev << "\n" << "" << _rateBiasMean << "\n" << "" << _rateBiasStdDev << "\n" << "\n" << "\n" << "" << _rateNoiseMean << "\n" << "" << _rateNoiseStdDev << "\n" << "" << _rateBiasMean << "\n" << "" << _rateBiasStdDev << "\n" << "\n" << "\n" << "" << _rateNoiseMean << "\n" << "" << _rateNoiseStdDev << "\n" << "" << _rateBiasMean << "\n" << "" << _rateBiasStdDev << "\n" << "\n" << "\n" << "\n" << "\n" << "" << _accelNoiseMean << "\n" << "" << _accelNoiseStdDev << "\n" << "" << _accelBiasMean << "\n" << "" << _accelBiasStdDev << "\n" << "\n" << "\n" << "" << _accelNoiseMean << "\n" << "" << _accelNoiseStdDev << "\n" << "" << _accelBiasMean << "\n" << "" << _accelBiasStdDev << "\n" << "\n" << "\n" << "" << _accelNoiseMean << "\n" << "" << _accelNoiseStdDev << "\n" << "" << _accelBiasMean << "\n" << "" << _accelBiasStdDev << "\n" << "\n" << "\n"; } newModelStr << " " << std::endl << " " << std::endl << "" << std::endl << "" << std::endl << "" << std::endl; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_modelName, 100, 1000); WaitUntilSensorSpawn(_imuSensorName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::SpawnUnitContactSensor(const std::string &_name, const std::string &_sensorName, const std::string &_collisionType, const math::Vector3 &_pos, const math::Vector3 &_rpy, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; std::ostringstream shapeStr; if (_collisionType == "box") { shapeStr << " 1 1 1"; } else if (_collisionType == "cylinder") { shapeStr << "" << " .51.0" << ""; } newModelStr << "" << "" << "" << _static << "" << "" << _pos << " " << _rpy << "" << "" << " " << " " << shapeStr.str() << " " << " " << " " << " " << " 0.005" << " " << " " << " " << " " << " " << " " << shapeStr.str() << " " << " " << " " << " " << " contact_collision" << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_name, 100, 100); WaitUntilSensorSpawn(_sensorName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::SpawnUnitImuSensor(const std::string &_name, const std::string &_sensorName, const std::string &_collisionType, const std::string &_topic, const math::Vector3 &_pos, const math::Vector3 &_rpy, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; std::ostringstream shapeStr; if (_collisionType == "box") shapeStr << " 1 1 1"; else if (_collisionType == "cylinder") { shapeStr << "" << " .51.0" << ""; } newModelStr << "" << "" << "" << _static << "" << "" << _pos << " " << _rpy << "" << "" << " " << " " << shapeStr.str() << " " << " " << " " << " " << " 0.01" << " " << " " << " " << " " << " " << " " << shapeStr.str() << " " << " " << " " << " " << " " << _topic << "" << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_name, 20, 50); WaitUntilSensorSpawn(_sensorName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::SpawnUnitAltimeterSensor(const std::string &_name, const std::string &_sensorName, const std::string &_collisionType, const std::string &_topic, const ignition::math::Vector3d &_pos, const ignition::math::Vector3d &_rpy, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; std::ostringstream shapeStr; if (_collisionType == "box") { shapeStr << " 1 1 1"; } else if (_collisionType == "cylinder") { shapeStr << "" << " .51.0" << ""; } newModelStr << "" << "" << "" << _static << "" << "" << _pos << " " << _rpy << "" << "" << " " << " " << shapeStr.str() << " " << " " << " " << " " << shapeStr.str() << " " << " " << " " << " " << _topic << "" << " " << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_name, 20, 50); WaitUntilSensorSpawn(_sensorName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::SpawnUnitMagnetometerSensor(const std::string &_name, const std::string &_sensorName, const std::string &_collisionType, const std::string &_topic, const ignition::math::Vector3d &_pos, const ignition::math::Vector3d &_rpy, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; std::ostringstream shapeStr; if (_collisionType == "box") { shapeStr << " 1 1 1"; } else if (_collisionType == "cylinder") { shapeStr << "" << " .51.0" << ""; } newModelStr << "" << "" << "" << _static << "" << "" << _pos << " " << _rpy << "" << "" << " " << " " << shapeStr.str() << " " << " " << " " << " " << shapeStr.str() << " " << " " << " " << " " << _topic << "" << " " << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_name, 20, 50); WaitUntilSensorSpawn(_sensorName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::launchTimeoutFailure(const char *_logMsg, const int _timeoutCS) { FAIL() << "ServerFixture timeout (wait more than " << _timeoutCS / 100 << "s): " << _logMsg; } ///////////////////////////////////////////////// void ServerFixture::SpawnWirelessTransmitterSensor(const std::string &_name, const std::string &_sensorName, const math::Vector3 &_pos, const math::Vector3 &_rpy, const std::string &_essid, double _freq, double _power, double _gain, bool _visualize) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "true" << "" << _pos << " " << _rpy << "" << "" << " " << " 1" << " 1" << " " << _visualize << "" << " " << " " << _essid << "" << " " << _freq << "" << " " << _power << "" << " " << _gain << "" << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_name, 100, 100); WaitUntilSensorSpawn(_sensorName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::SpawnWirelessReceiverSensor(const std::string &_name, const std::string &_sensorName, const math::Vector3 &_pos, const math::Vector3 &_rpy, double _minFreq, double _maxFreq, double _power, double _gain, double _sensitivity, bool _visualize) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "true" << "" << _pos << " " << _rpy << "" << "" << " " << " 1" << " " << _visualize << "" << " " << " " << _minFreq << "" << " " << _maxFreq << "" << " " << _power << "" << " " << _gain << "" << " " << _sensitivity << "" << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); WaitUntilEntitySpawn(_name, 100, 100); WaitUntilSensorSpawn(_sensorName, 100, 100); } ///////////////////////////////////////////////// void ServerFixture::WaitUntilEntitySpawn(const std::string &_name, unsigned int _sleepEach, int _retries) { int i = 0; // Wait for the entity to spawn while (!this->HasEntity(_name) && i < _retries) { common::Time::MSleep(_sleepEach); ++i; } EXPECT_LT(i, _retries); if (i >= _retries) FAIL() << "ServerFixture timeout: max number of retries (" << _retries << ") exceeded while awaiting the spawn of " << _name; } ///////////////////////////////////////////////// void ServerFixture::WaitUntilSensorSpawn(const std::string &_name, unsigned int _sleepEach, int _retries) { int i = 0; // Wait for the sensor to spawn while (!sensors::get_sensor(_name) && i < _retries) { common::Time::MSleep(_sleepEach); ++i; } EXPECT_LT(i, _retries); if (i >= _retries) FAIL() << "ServerFixture timeout: max number of retries (" << _retries << ") exceeded while awaiting the spawn of " << _name; } ///////////////////////////////////////////////// void ServerFixture::WaitUntilIteration(const uint32_t _goalIteration, const int _sleepEach, const int _retries) const { int i = 0; auto world = physics::get_world(); while ((world->GetIterations() != _goalIteration) && (i < _retries)) { ++i; common::Time::MSleep(_sleepEach); } } ///////////////////////////////////////////////// void ServerFixture::WaitUntilSimTime(const common::Time &_goalTime, const int _sleepEach, const int _retries) const { int i = 0; auto world = physics::get_world(); while ((world->GetSimTime() != _goalTime) && (i < _retries)) { ++i; common::Time::MSleep(_sleepEach); } } ///////////////////////////////////////////////// void ServerFixture::SpawnLight(const std::string &_name, const std::string &_type, const math::Vector3 &_pos, const math::Vector3 &_rpy, const common::Color &_diffuse, const common::Color &_specular, const math::Vector3 &_direction, double _attenuationRange, double _attenuationConstant, double _attenuationLinear, double _attenuationQuadratic, double _spotInnerAngle, double _spotOuterAngle, double _spotFallOff, bool _castShadows) { msgs::Factory msg; std::ostringstream newLightStr; newLightStr << "" << "" << "" << _pos << " " << _rpy << "" << "" << _diffuse << "" << "" << _specular << "" << "" << _direction << "" << "" << " " << _attenuationRange << "" << " " << _attenuationConstant << "" << " " << _attenuationLinear << "" << " " << _attenuationQuadratic << "" << ""; if (_type == "spot") { newLightStr << "" << " " << _spotInnerAngle << "" << " " << _spotOuterAngle << "" << " " << _spotFallOff << "" << ""; } newLightStr << "" << _castShadows << "" << "" << ""; msg.set_sdf(newLightStr.str()); this->factoryPub->Publish(msg); physics::WorldPtr world = physics::get_world(); msgs::Scene sceneMsg; int timeOutCount = 0; int maxTimeOut = 10; while (timeOutCount < maxTimeOut) { sceneMsg = world->GetSceneMsg(); for (int i = 0; i < sceneMsg.light_size(); ++i) { if (sceneMsg.light(i).name() == _name) break; } timeOutCount++; common::Time::MSleep(100); } } ///////////////////////////////////////////////// void ServerFixture::SpawnCylinder(const std::string &_name, const math::Vector3 &_pos, const math::Vector3 &_rpy, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; msgs::Model model; model.set_name(_name); model.set_is_static(_static); msgs::Set(model.mutable_pose(), ignition::math::Pose3d(_pos.Ign(), ignition::math::Quaterniond(_rpy.Ign()))); msgs::AddCylinderLink(model, 1.0, 0.5, 1.0); auto link = model.mutable_link(0); link->set_name("body"); link->mutable_collision(0)->set_name("geom"); newModelStr << "" << msgs::ModelToSDF(model)->ToString("") << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); // Wait for the entity to spawn while (!this->HasEntity(_name)) common::Time::MSleep(100); } ///////////////////////////////////////////////// void ServerFixture::SpawnSphere(const std::string &_name, const math::Vector3 &_pos, const math::Vector3 &_rpy, bool _wait, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "" << _static << "" << "" << _pos << " " << _rpy << "" << "" << " " << " " << " .5" << " " << " " << " " << " " << " .5" << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); // Wait for the entity to spawn while (_wait && !this->HasEntity(_name)) common::Time::MSleep(100); } ///////////////////////////////////////////////// void ServerFixture::SpawnSphere(const std::string &_name, const math::Vector3 &_pos, const math::Vector3 &_rpy, const math::Vector3 &_cog, double _radius, bool _wait, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; msgs::Model model; model.set_name(_name); model.set_is_static(_static); msgs::Set(model.mutable_pose(), ignition::math::Pose3d(_pos.Ign(), ignition::math::Quaterniond(_rpy.Ign()))); msgs::AddSphereLink(model, 1.0, _radius); auto link = model.mutable_link(0); link->set_name("body"); link->mutable_collision(0)->set_name("geom"); msgs::Set(link->mutable_inertial()->mutable_pose(), ignition::math::Pose3d(_cog.Ign(), ignition::math::Quaterniond())); newModelStr << "" << msgs::ModelToSDF(model)->ToString("") << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); // Wait for the entity to spawn while (_wait && !this->HasEntity(_name)) common::Time::MSleep(100); } ///////////////////////////////////////////////// void ServerFixture::SpawnBox(const std::string &_name, const math::Vector3 &_size, const math::Vector3 &_pos, const math::Vector3 &_rpy, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; msgs::Model model; model.set_name(_name); model.set_is_static(_static); msgs::Set(model.mutable_pose(), ignition::math::Pose3d(_pos.Ign(), ignition::math::Quaterniond(_rpy.Ign()))); msgs::AddBoxLink(model, 1.0, _size.Ign()); auto link = model.mutable_link(0); link->set_name("body"); link->mutable_collision(0)->set_name("geom"); newModelStr << "" << msgs::ModelToSDF(model)->ToString("") << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); // Wait for the entity to spawn while (!this->HasEntity(_name)) common::Time::MSleep(100); } ///////////////////////////////////////////////// void ServerFixture::SpawnTrimesh(const std::string &_name, const std::string &_modelPath, const math::Vector3 &_scale, const math::Vector3 &_pos, const math::Vector3 &_rpy, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; newModelStr << "" << "" << "" << _static << "" << "" << _pos << " " << _rpy << "" << "" << " " << " " << " " << " " << _modelPath << "" << " " << _scale << "" << " " << " " << " " << " " << " " << " " << _modelPath << "" << " " << " " << "" << "" << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); // Wait for the entity to spawn while (!this->HasEntity(_name)) common::Time::MSleep(100); } ///////////////////////////////////////////////// void ServerFixture::SpawnEmptyLink(const std::string &_name, const math::Vector3 &_pos, const math::Vector3 &_rpy, bool _static) { msgs::Factory msg; std::ostringstream newModelStr; msgs::Model model; model.set_name(_name); model.set_is_static(_static); msgs::Set(model.mutable_pose(), ignition::math::Pose3d(_pos.Ign(), ignition::math::Quaterniond(_rpy.Ign()))); model.add_link(); model.mutable_link(0)->set_name("body"); newModelStr << "" << msgs::ModelToSDF(model)->ToString("") << ""; msg.set_sdf(newModelStr.str()); this->factoryPub->Publish(msg); // Wait for the entity to spawn while (!this->HasEntity(_name)) common::Time::MSleep(100); } ///////////////////////////////////////////////// void ServerFixture::SpawnModel(const std::string &_filename) { msgs::Factory msg; msg.set_sdf_filename(_filename); this->factoryPub->Publish(msg); } ///////////////////////////////////////////////// void ServerFixture::SpawnSDF(const std::string &_sdf) { msgs::Factory msg; msg.set_sdf(_sdf); this->factoryPub->Publish(msg); // The code above sends a message, but it will take some time // before the message is processed. // // The code below parses the sdf string to find a model name, // then this function will block until that model // has been processed and recognized by the Server Fixture. sdf::SDF sdfParsed; sdfParsed.SetFromString(_sdf); // Check that sdf contains a model if (sdfParsed.Root()->HasElement("model")) { // Timeout of 30 seconds (3000 * 10 ms) int waitCount = 0, maxWaitCount = 3000; sdf::ElementPtr model = sdfParsed.Root()->GetElement("model"); std::string name = model->Get("name"); while (!this->HasEntity(name) && ++waitCount < maxWaitCount) common::Time::MSleep(100); ASSERT_LT(waitCount, maxWaitCount); } } ///////////////////////////////////////////////// void ServerFixture::LoadPlugin(const std::string &_filename, const std::string &_name) { // Get the first world...we assume it the only one running physics::WorldPtr world = physics::get_world(); world->LoadPlugin(_filename, _name, sdf::ElementPtr()); } ///////////////////////////////////////////////// physics::ModelPtr ServerFixture::GetModel(const std::string &_name) { // Get the first world...we assume it the only one running physics::WorldPtr world = physics::get_world(); return world->GetModel(_name); } ///////////////////////////////////////////////// void ServerFixture::RemoveModel(const std::string &_name) { msgs::Request *msg = msgs::CreateRequest("entity_delete", _name); this->requestPub->Publish(*msg); delete msg; } ///////////////////////////////////////////////// void ServerFixture::RemovePlugin(const std::string &_name) { // Get the first world...we assume it the only one running physics::WorldPtr world = physics::get_world(); world->RemovePlugin(_name); } ///////////////////////////////////////////////// void ServerFixture::GetMemInfo(double &_resident, double &_share) { #ifdef __linux__ int totalSize, residentPages, sharePages; totalSize = residentPages = sharePages = 0; std::ifstream buffer("/proc/self/statm"); buffer >> totalSize >> residentPages >> sharePages; buffer.close(); // in case x86-64 is configured to use 2MB pages int64_t pageSizeKb = sysconf(_SC_PAGE_SIZE) / 1024; _resident = residentPages * pageSizeKb; _share = sharePages * pageSizeKb; #elif __MACH__ // /proc is only available on Linux // for OSX, use task_info to get resident and virtual memory struct task_basic_info t_info; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; if (KERN_SUCCESS != task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)) { gzerr << "failure calling task_info\n"; return; } _resident = static_cast(t_info.resident_size/1024); _share = static_cast(t_info.virtual_size/1024); #else gzerr << "Unsupported architecture\n"; return; #endif } ///////////////////////////////////////////////// std::string ServerFixture::GetUniqueString(const std::string &_prefix) { std::ostringstream stream; stream << _prefix << this->uniqueCounter++; return stream.str(); }