/* * 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 "gazebo/msgs/msgs.hh" #include "gazebo/transport/transport.hh" #include "gazebo/sensors/SensorsIface.hh" #include "ModelPropShop.hh" using namespace gazebo; namespace po = boost::program_options; // Register this plugin with the simulator GZ_REGISTER_SYSTEM_PLUGIN(ModelPropShop) ///////////////////////////////////////////// ModelPropShop::~ModelPropShop() { rendering::fini(); } ///////////////////////////////////////////// void ModelPropShop::Load(int _argc, char **_argv) { // Turn off sensors. gazebo::sensors::disable(); po::options_description v_desc("Options"); v_desc.add_options() ("propshop-save", po::value(), "Path to save image files into.") ("propshop-model", po::value(), "Model to spawn."); po::options_description desc("Options"); desc.add(v_desc); po::variables_map vm; try { po::store(po::command_line_parser(_argc, _argv).options( desc).allow_unregistered().run(), vm); po::notify(vm); } catch(boost::exception &_e) { std::cerr << "Error. Invalid arguments\n"; return; } // Get the directory in which to save the images. if (vm.count("propshop-save")) { this->savePath = boost::filesystem::path( vm["propshop-save"].as()); if (!boost::filesystem::exists(this->savePath)) boost::filesystem::create_directories(this->savePath); } else this->savePath = boost::filesystem::temp_directory_path(); std::string modelFile; if (vm.count("propshop-model")) modelFile = vm["propshop-model"].as(); else return; std::ifstream ifs(modelFile.c_str()); if (!ifs) { std::cerr << "Error: Unable to open file[" << modelFile << "]\n"; return; } this->sdf.reset(new sdf::SDF()); if (!sdf::init(this->sdf)) { std::cerr << "ERROR: SDF parsing the xml failed" << std::endl; return; } if (!sdf::readFile(modelFile, this->sdf)) { std::cerr << "Error: SDF parsing the xml failed\n"; return; } sdf::ElementPtr modelElem = this->sdf->Root()->GetElement("model"); this->modelName = modelElem->Get("name"); } ///////////////////////////////////////////// void ModelPropShop::Init() { this->worldCreatedConn = event::Events::ConnectWorldCreated( boost::bind(&ModelPropShop::OnWorldCreated, this)); this->updateConn = event::Events::ConnectWorldUpdateBegin( boost::bind(&ModelPropShop::Update, this)); this->node = transport::NodePtr(new transport::Node()); this->node->Init(); this->pub = this->node->Advertise( "/gazebo/server/control"); this->factoryPub = this->node->Advertise("~/factory"); } ///////////////////////////////////////////// void ModelPropShop::OnWorldCreated() { this->factoryPub->WaitForConnection(); if (this->sdf) { msgs::Factory msg; msg.set_sdf(this->sdf->ToString()); this->factoryPub->Publish(msg, true); } } ///////////////////////////////////////////// void ModelPropShop::Update() { // Make sure to initialize the rendering engine in the same thread that will // capture images. if (!this->scene) { rendering::load(); rendering::init(); sdf::ElementPtr cameraSDF(new sdf::Element); sdf::initFile("camera.sdf", cameraSDF); this->scene = rendering::create_scene("default", false, true); this->camera = this->scene->CreateCamera("propshopcamera", false); this->camera->SetCaptureData(true); this->camera->Load(cameraSDF); this->camera->Init(); this->camera->SetHFOV(static_cast(IGN_DTOR(60))); this->camera->SetImageWidth(960); this->camera->SetImageHeight(540); this->camera->CreateRenderTexture("ModelPropShop_RttTex"); // Create a light gazebo::msgs::Light lightMsg; lightMsg.set_name("propshop_light"); lightMsg.set_type(gazebo::msgs::Light::DIRECTIONAL); gazebo::msgs::Set(lightMsg.mutable_diffuse(), gazebo::common::Color(1, 1, 1, 1)); gazebo::msgs::Set(lightMsg.mutable_specular(), gazebo::common::Color(.2, .2, .2, 1)); gazebo::msgs::Set(lightMsg.mutable_direction(), ignition::math::Vector3d(-0.5, 0.1, -0.9)); lightMsg.set_cast_shadows(false); lightMsg.set_range(1000); lightMsg.set_attenuation_constant(1); lightMsg.set_attenuation_linear(0); lightMsg.set_attenuation_quadratic(0); this->light.reset(new gazebo::rendering::Light(this->scene)); light->LoadFromMsg(lightMsg); gazebo::rendering::RTShaderSystem::Instance()->UpdateShaders(); return; } if (this->camera && this->scene) event::Events::preRender(); if (this->camera && this->scene->Initialized() && this->camera->Initialized()) { rendering::VisualPtr vis = this->scene->GetVisual(this->modelName); if (vis) { math::Box bbox = vis->GetBoundingBox(); // Compute model scaling. double scaling = 1.0 / bbox.GetSize().GetMax(); // Compute the model translation. math::Vector3 trans = bbox.GetCenter(); trans *= -scaling; // Normalize the size of the visual vis->SetScale(math::Vector3(scaling, scaling, scaling)); vis->SetWorldPose(math::Pose(trans.x, trans.y, trans.z, 0, 0, 0)); // Place the visual at the origin bbox = vis->GetBoundingBox(); ignition::math::Pose3d pose; // Perspective view pose.Pos().Set(1.6, -1.6, 1.2); pose.Rot().Euler(0, IGN_DTOR(30), IGN_DTOR(-225)); this->light->SetDirection(ignition::math::Vector3d(-0.4, 0.4, -0.4)); this->camera->SetWorldPose(pose); this->camera->Update(); this->camera->Render(true); this->camera->PostRender(); this->camera->SaveFrame((this->savePath / "1.png").string()); // Top view pose.Pos().Set(0, 0, 2.2); pose.Rot().Euler(0, IGN_DTOR(90), 0); this->light->SetDirection(ignition::math::Vector3d(0, 0, -1.0)); this->camera->SetWorldPose(pose); this->camera->Update(); this->camera->Render(true); this->camera->PostRender(); this->camera->SaveFrame((this->savePath / "2.png").string()); // Front view pose.Pos().Set(2.2, 0, 0); pose.Rot().Euler(0, 0, IGN_DTOR(-180)); this->light->SetDirection(ignition::math::Vector3d(-0.6, 0.0, -0.4)); this->camera->SetWorldPose(pose); this->camera->Update(); this->camera->Render(true); this->camera->PostRender(); this->camera->SaveFrame((this->savePath / "3.png").string()); // Side view pose.Pos().Set(0, 2.2, 0); pose.Rot().Euler(0, 0, IGN_DTOR(-90)); this->light->SetDirection(ignition::math::Vector3d(0, -0.6, -0.4)); this->camera->SetWorldPose(pose); this->camera->Update(); this->camera->Render(true); this->camera->PostRender(); this->camera->SaveFrame((this->savePath / "4.png").string()); // Back view pose.Pos().Set(-2.2, 0, 0); pose.Rot().Euler(0, 0, 0); this->light->SetDirection(ignition::math::Vector3d(0.6, 0, -0.4)); this->camera->SetWorldPose(pose); this->camera->Update(); this->camera->Render(true); this->camera->PostRender(); this->camera->SaveFrame((this->savePath / "5.png").string()); event::Events::DisconnectWorldCreated(this->worldCreatedConn); this->worldCreatedConn.reset(); event::Events::DisconnectWorldUpdateBegin(this->updateConn); this->updateConn.reset(); // Clean up the camera. this->camera.reset(); this->light.reset(); this->scene->RemoveCamera("propshopcamera"); // Tell the server to stop. msgs::ServerControl msg; msg.set_stop(true); this->pub->Publish(msg); } } }