-
Notifications
You must be signed in to change notification settings - Fork 269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Modelpropshop gazebo plugin port #1331
Merged
Merged
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
387aaa7
first working version of modelpropshop plugin
b7a0ac7
background, random joints and some refactoring
8b12d5c
moving camera to center object in image
43dc07d
Update src/systems/model_photo_shoot/ModelPhotoShoot.cc
marcoag d16f688
several fixes to address PR suggestions
4c64557
adding tutorials and fixes to PR comments
ebcf122
Update src/systems/model_photo_shoot/ModelPhotoShoot.cc
marcoag 00dbb5c
Update src/systems/model_photo_shoot/ModelPhotoShoot.cc
marcoag bbbf263
Merge branch 'ign-gazebo5' into marcoag/model_propshop
marcoag 3f1e5a4
fixes to github commits
cd6f7c6
Update examples/worlds/model_photo_shoot.sdf
marcoag a712a0e
adding jointType checks
b0dc697
lint fixes
c0c14b0
adding exmple world location
2ed80f3
adding model photo shoot test
2eefd53
Merge branch 'ign-gazebo5' into marcoag/model_propshop
marcoag 8899e20
adding random joints test
bb3d391
adding copyright message
e0965ca
plugin adds JointPosition component with position
40796db
fixed comment
c17a158
Merge branch 'ign-gazebo5' into marcoag/model_propshop
azeey 59a8870
Enable test only on Linux
azeey a9dee08
Create unique directory for test
azeey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<?xml version="1.0" ?> | ||
<!-- | ||
Ignition Gazebo Model Photo Shoot plugin demo | ||
This will take perspective, top, front, and both sides pictures of the model: | ||
ign gazebo -s -r -v 4 \-\-iterations 50 model_photo_shoot.sdf | ||
--> | ||
<sdf version="1.6"> | ||
<world name="default"> | ||
<gravity>0 0 0</gravity> | ||
<plugin | ||
filename="ignition-gazebo-physics-system" | ||
name="ignition::gazebo::systems::Physics"> | ||
</plugin> | ||
<plugin | ||
filename="ignition-gazebo-sensors-system" | ||
name="ignition::gazebo::systems::Sensors"> | ||
<render_engine>ogre2</render_engine> | ||
<background_color>1, 1, 1</background_color> | ||
</plugin> | ||
<include> | ||
<uri>https://fuel.ignitionrobotics.org/1.0/OpenRobotics/models/Robonaut</uri> | ||
<plugin | ||
filename="ignition-gazebo-model-photo-shoot-system" | ||
name="ignition::gazebo::systems::ModelPhotoShoot"> | ||
<translation_data_file>poses.txt</translation_data_file> | ||
<random_joints_pose>false</random_joints_pose> | ||
</plugin> | ||
</include> | ||
<model name="photo_shoot"> | ||
<link name="link"> | ||
<pose>0 0 0 0 0 0</pose> | ||
<sensor name="camera" type="camera"> | ||
<camera> | ||
<horizontal_fov>1.047</horizontal_fov> | ||
<image> | ||
<width>960</width> | ||
<height>540</height> | ||
</image> | ||
<clip> | ||
<near>0.1</near> | ||
<far>100</far> | ||
</clip> | ||
</camera> | ||
<always_on>1</always_on> | ||
<update_rate>30</update_rate> | ||
<visualize>true</visualize> | ||
<topic>camera</topic> | ||
</sensor> | ||
</link> | ||
<static>true</static> | ||
</model> | ||
</world> | ||
</sdf> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
gz_add_system(model-photo-shoot | ||
SOURCES | ||
ModelPhotoShoot.cc | ||
PUBLIC_LINK_LIBS | ||
ignition-common${IGN_COMMON_VER}::ignition-common${IGN_COMMON_VER} | ||
ignition-rendering${IGN_RENDERING_VER}::ignition-rendering${IGN_RENDERING_VER} | ||
ignition-transport${IGN_TRANSPORT_VER}::ignition-transport${IGN_TRANSPORT_VER} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,303 @@ | ||
/* | ||
* Copyright (C) 2019 Open Source Robotics Foundation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: 2022 |
||
* | ||
* 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 "ModelPhotoShoot.hh" | ||
|
||
#include <random> | ||
#include <string> | ||
#include <vector> | ||
|
||
#include <ignition/common/Image.hh> | ||
#include <ignition/plugin/Register.hh> | ||
#include <ignition/rendering/Camera.hh> | ||
#include <ignition/rendering/Scene.hh> | ||
#include <ignition/rendering/RenderingIface.hh> | ||
#include <ignition/rendering/Visual.hh> | ||
|
||
#include "ignition/gazebo/components/Joint.hh" | ||
#include "ignition/gazebo/components/JointAxis.hh" | ||
#include "ignition/gazebo/components/JointType.hh" | ||
#include "ignition/gazebo/components/JointPositionReset.hh" | ||
#include "ignition/gazebo/components/Name.hh" | ||
#include "ignition/gazebo/components/Pose.hh" | ||
#include "ignition/gazebo/Model.hh" | ||
#include "ignition/gazebo/rendering/Events.hh" | ||
#include "ignition/gazebo/Util.hh" | ||
|
||
using namespace ignition; | ||
using namespace gazebo; | ||
using namespace systems; | ||
|
||
/// \brief Private ModelPhotoShoot data class. | ||
class ignition::gazebo::systems::ModelPhotoShootPrivate | ||
{ | ||
/// \brief Callback for pos rendering operations. | ||
public: void PerformPostRenderingOperations(); | ||
|
||
/// \brief Save a pitcture with the camera from the given pose. | ||
public: void SavePicture (const ignition::rendering::CameraPtr _camera, | ||
const ignition::math::Pose3d &_pose, | ||
const std::string &_fileName) const; | ||
|
||
/// \brief Name of the loaded model. | ||
public: std::string modelName; | ||
|
||
/// \brief model | ||
public: std::shared_ptr<ignition::gazebo::Model> model; | ||
|
||
/// \brief model world pose | ||
public: ignition::math::Pose3d modelPose3D; | ||
|
||
/// \brief Connection to pre-render event callback. | ||
public: ignition::common::ConnectionPtr connection{nullptr}; | ||
|
||
/// \brief Boolean to control we only take the pictures once. | ||
public: bool takePicture{true}; | ||
|
||
/// \brief Boolean to control if joints should adopt random poses. | ||
public: bool randomPoses{false}; | ||
|
||
/// \brief File to save translation and scaling info. | ||
public: std::ofstream savingFile; | ||
}; | ||
|
||
////////////////////////////////////////////////// | ||
ModelPhotoShoot::ModelPhotoShoot() | ||
: System(), dataPtr(std::make_unique<ModelPhotoShootPrivate>()) | ||
{ | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
void ModelPhotoShoot::Configure(const ignition::gazebo::Entity &_entity, | ||
const std::shared_ptr<const sdf::Element> &_sdf, | ||
ignition::gazebo::EntityComponentManager &_ecm, | ||
ignition::gazebo::EventManager &_eventMgr) | ||
{ | ||
std::string saveDataLocation = | ||
_sdf->Get<std::string>("translation_data_file"); | ||
if (saveDataLocation.empty()) | ||
{ | ||
igndbg << "No data location specified, skipping translaiton data" | ||
"saving.\n"; | ||
} | ||
else | ||
{ | ||
igndbg << "Saving translation data to: " | ||
<< saveDataLocation << std::endl; | ||
this->dataPtr->savingFile.open(saveDataLocation); | ||
} | ||
|
||
if (_sdf->HasElement("random_joints_pose")) | ||
{ | ||
this->dataPtr->randomPoses = _sdf->Get<bool>("random_joints_pose"); | ||
} | ||
|
||
this->dataPtr->connection = | ||
_eventMgr.Connect<ignition::gazebo::events::PostRender>(std::bind( | ||
&ModelPhotoShootPrivate::PerformPostRenderingOperations, | ||
this->dataPtr.get())); | ||
|
||
this->dataPtr->model = std::make_shared<ignition::gazebo::Model>(_entity); | ||
this->dataPtr->modelName = this->dataPtr->model->Name(_ecm); | ||
// Get the pose of the model | ||
this->dataPtr->modelPose3D = | ||
ignition::gazebo::worldPose(this->dataPtr->model->Entity(), _ecm); | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
void ModelPhotoShoot::PreUpdate( | ||
const ignition::gazebo::UpdateInfo &, | ||
ignition::gazebo::EntityComponentManager &_ecm) | ||
{ | ||
if (this->dataPtr->randomPoses) | ||
{ | ||
std::vector<gazebo::Entity> joints = this->dataPtr->model->Joints(_ecm); | ||
unsigned seed = | ||
std::chrono::system_clock::now().time_since_epoch().count(); | ||
std::default_random_engine generator(seed); | ||
for (const auto &joint : joints) | ||
{ | ||
auto jointNameComp = _ecm.Component<components::Name>(joint); | ||
if (jointNameComp) | ||
{ | ||
auto jointType = _ecm.Component<components::JointType>(joint)->Data(); | ||
if (jointType != sdf::JointType::FIXED) | ||
{ | ||
if (jointType == sdf::JointType::REVOLUTE || | ||
jointType == sdf::JointType::PRISMATIC) | ||
{ | ||
// Using the JointAxis component to extract the joint pose limits | ||
auto jointAxisComp = _ecm.Component<components::JointAxis>(joint); | ||
if (jointAxisComp) | ||
{ | ||
std::uniform_real_distribution<double> distribution( | ||
jointAxisComp->Data().Lower(), | ||
jointAxisComp->Data().Upper()); | ||
double jointPose = distribution(generator); | ||
_ecm.SetComponentData<components::JointPositionReset>( | ||
joint, {jointPose}); | ||
if (this->dataPtr->savingFile.is_open()) | ||
{ | ||
this->dataPtr->savingFile << jointNameComp->Data() << ": " | ||
<< jointPose << std::endl; | ||
} | ||
} | ||
else | ||
{ | ||
ignerr << "No jointAxisComp found, ignoring joint: " << | ||
jointNameComp->Data() << std::endl; | ||
} | ||
} | ||
else | ||
{ | ||
ignerr << "Model Photo Shoot only supports single axis joints. " | ||
"Skipping joint: "<< jointNameComp->Data() << std::endl; | ||
} | ||
} | ||
else | ||
{ | ||
igndbg << "Ignoring fixed joint: " << jointNameComp->Data() << | ||
std::endl; | ||
} | ||
} | ||
else | ||
{ | ||
ignerr << "No jointNameComp found on entity: " << joint << | ||
std:: endl; | ||
} | ||
} | ||
// Only set random joint poses once | ||
this->dataPtr->randomPoses = false; | ||
} | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
void ModelPhotoShootPrivate::PerformPostRenderingOperations() | ||
{ | ||
ignition::rendering::ScenePtr scene = | ||
ignition::rendering::sceneFromFirstRenderEngine(); | ||
ignition::rendering::VisualPtr modelVisual = | ||
scene->VisualByName(this->modelName); | ||
|
||
ignition::rendering::VisualPtr root = scene->RootVisual(); | ||
|
||
if (modelVisual && this->takePicture) | ||
{ | ||
scene->SetAmbientLight(0.3, 0.3, 0.3); | ||
|
||
// create directional light | ||
ignition::rendering::DirectionalLightPtr light0 = | ||
scene->CreateDirectionalLight(); | ||
light0->SetDirection(-0.5, 0.5, -1); | ||
light0->SetDiffuseColor(0.8, 0.8, 0.8); | ||
light0->SetSpecularColor(0.5, 0.5, 0.5); | ||
root->AddChild(light0); | ||
|
||
// create point light | ||
ignition::rendering::PointLightPtr light2 = scene->CreatePointLight(); | ||
light2->SetDiffuseColor(0.5, 0.5, 0.5); | ||
light2->SetSpecularColor(0.5, 0.5, 0.5); | ||
light2->SetLocalPosition(3, 5, 5); | ||
root->AddChild(light2); | ||
|
||
for (unsigned int i = 0; i < scene->NodeCount(); ++i) | ||
{ | ||
auto camera = std::dynamic_pointer_cast<ignition::rendering::Camera>( | ||
scene->NodeByIndex(i)); | ||
if (nullptr != camera && camera->Name() == "photo_shoot::link::camera") | ||
{ | ||
// Compute the translation we have to apply to the cameras to | ||
// center the model in the image. | ||
ignition::math::AxisAlignedBox bbox = modelVisual->LocalBoundingBox(); | ||
double scaling = 1.0 / bbox.Size().Max(); | ||
ignition::math::Vector3d bboxCenter = bbox.Center(); | ||
ignition::math::Vector3d translation = | ||
bboxCenter + this->modelPose3D.Pos(); | ||
if (this->savingFile.is_open()) { | ||
this->savingFile << "Translation: " << translation << std::endl; | ||
this->savingFile << "Scaling: " << scaling << std::endl; | ||
} | ||
|
||
ignition::math::Pose3d pose; | ||
// Perspective view | ||
pose.Pos().Set(1.6 / scaling + translation.X(), | ||
-1.6 / scaling + translation.Y(), | ||
1.2 / scaling + translation.Z()); | ||
pose.Rot().Euler(0, IGN_DTOR(30), IGN_DTOR(-225)); | ||
SavePicture(camera, pose, "1.png"); | ||
|
||
// Top view | ||
pose.Pos().Set(0 + translation.X(), | ||
0 + translation.Y(), | ||
2.2 / scaling + translation.Z()); | ||
pose.Rot().Euler(0, IGN_DTOR(90), 0); | ||
SavePicture(camera, pose, "2.png"); | ||
|
||
// Front view | ||
pose.Pos().Set(2.2 / scaling + translation.X(), | ||
0 + translation.Y(), | ||
0 + translation.Z()); | ||
pose.Rot().Euler(0, 0, IGN_DTOR(-180)); | ||
SavePicture(camera, pose, "3.png"); | ||
|
||
// Side view | ||
pose.Pos().Set(0 + translation.X(), | ||
2.2 / scaling + translation.Y(), | ||
0 + translation.Z()); | ||
pose.Rot().Euler(0, 0, IGN_DTOR(-90)); | ||
SavePicture(camera, pose, "4.png"); | ||
|
||
// Back view | ||
pose.Pos().Set(-2.2 / scaling + translation.X(), | ||
0 + translation.Y(), | ||
0 + translation.Z()); | ||
pose.Rot().Euler(0, 0, 0); | ||
SavePicture(camera, pose, "5.png"); | ||
|
||
this->takePicture = false; | ||
} | ||
} | ||
} | ||
} | ||
|
||
////////////////////////////////////////////////// | ||
void ModelPhotoShootPrivate::SavePicture( | ||
const ignition::rendering::CameraPtr _camera, | ||
const ignition::math::Pose3d &_pose, | ||
const std::string &_fileName) const | ||
{ | ||
unsigned int width = _camera->ImageWidth(); | ||
unsigned int height = _camera->ImageHeight(); | ||
ignition::common::Image image; | ||
|
||
_camera->SetWorldPose(_pose); | ||
auto cameraImage = _camera->CreateImage(); | ||
_camera->Capture(cameraImage); | ||
auto formatStr = | ||
ignition::rendering::PixelUtil::Name(_camera->ImageFormat()); | ||
auto format = ignition::common::Image::ConvertPixelFormat(formatStr); | ||
image.SetFromData(cameraImage.Data<unsigned char>(), width, height, format); | ||
image.SavePNG(_fileName); | ||
|
||
igndbg << "Saved image to [" << _fileName << "]" << std::endl; | ||
} | ||
|
||
IGNITION_ADD_PLUGIN(ModelPhotoShoot, ignition::gazebo::System, | ||
ModelPhotoShoot::ISystemConfigure, | ||
ModelPhotoShoot::ISystemPreUpdate) | ||
|
||
IGNITION_ADD_PLUGIN_ALIAS(ModelPhotoShoot, | ||
"ignition::gazebo::systems::ModelPhotoShoot") |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add the command to run
ign-gazebo
as in the other example sdf files? Perhaps include the number of iterations.