Skip to content
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

Support recreating model entities #1170

Merged
merged 40 commits into from
Nov 17, 2021
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c4a0516
add recreate component and implement recreate entities functionality,…
iche033 Nov 5, 2021
2f3b87f
update test and make recreate entities with same name work
iche033 Nov 5, 2021
d10bfec
revert add include
iche033 Nov 5, 2021
2e6c570
style
iche033 Nov 5, 2021
0cf71a9
Merge branch 'ign-gazebo6' into recreate_entities
iche033 Nov 5, 2021
18b26c2
Support editing air pressure sensor in the GUI
Nov 6, 2021
1477a68
Add noise to qrc
Nov 6, 2021
92bed4e
Add noise to qrc
Nov 6, 2021
d553e8f
Merge branch 'ign-gazebo6' into air_pressure_component_inspector
mjcarroll Nov 8, 2021
103cdf0
Fix lint
mjcarroll Nov 8, 2021
c4eb390
Merge branch 'ign-gazebo6' into air_pressure_component_inspector
Nov 8, 2021
2029d2b
Update sensor icon
Nov 8, 2021
9fa9a84
Merge branch 'air_pressure_component_inspector' of github.com:ignitio…
Nov 8, 2021
2d8d50f
Move AirPressure functions out of ComponentInspector (#1179)
chapulina Nov 9, 2021
1a3b5ee
Fix get decimals, and address comments
Nov 9, 2021
8d0b08d
merged
Nov 9, 2021
c2898a8
merged
Nov 9, 2021
5c0a4c0
cleanup and simplification
Nov 9, 2021
39a1d34
check recreate comp in ancestor
iche033 Nov 9, 2021
d139bd1
require sdf 12.1.0
Nov 9, 2021
d56e983
Revert sdf version requirement
Nov 9, 2021
638d43d
Merge branch 'air_pressure_component_inspector' of github.com:ignitio…
Nov 9, 2021
68faa5a
Fix codecheck
Nov 9, 2021
2775d05
revert my bad merge
Nov 10, 2021
8f7fe57
remvoe sensor icon
Nov 10, 2021
370ffd2
Merge branch 'model_editor' into recreate_entities
Nov 10, 2021
304d004
Together (#1187)
nkoenig Nov 11, 2021
14d78f3
Address comments
Nov 11, 2021
cdee88d
update cameras list on sensor removal
iche033 Nov 12, 2021
8a6552e
update cameras list on sensor removal
iche033 Nov 12, 2021
f399b49
Merge branch 'recreate_entities' of github.com:ignitionrobotics/ign-g…
iche033 Nov 12, 2021
c897c41
Require sensors 6.1
Nov 12, 2021
0ab3217
sensors 6.0.1
Nov 12, 2021
0576793
Test model recreation with jointed models
mjcarroll Nov 12, 2021
9932f2a
Fix multiple joints with same names
mjcarroll Nov 15, 2021
df289fb
Recreate entities joints (#1206)
mjcarroll Nov 15, 2021
29a2cac
Fix the ecm test, which had bad parent-child relationships between li…
Nov 16, 2021
f4df9c9
Merge branch 'recreate_entities_joints' into recreate_entities
Nov 16, 2021
ff40d98
Added test for world joints
Nov 16, 2021
fcfc6e0
Merge branch 'recreate_entities_joints' into recreate_entities
Nov 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions include/ignition/gazebo/components/Recreate.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2021 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.
*
*/
#ifndef IGNITION_GAZEBO_COMPONENTS_RECREATE_HH_
#define IGNITION_GAZEBO_COMPONENTS_RECREATE_HH_

#include <ignition/gazebo/components/Factory.hh>
#include <ignition/gazebo/components/Component.hh>
#include <ignition/gazebo/config.hh>

namespace ignition
{
namespace gazebo
{
// Inline bracket to help doxygen filtering.
inline namespace IGNITION_GAZEBO_VERSION_NAMESPACE {
namespace components
{
/// \brief A component that identifies an entity needs to be recreated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we document how the component is used?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added documentation in 14d78f3

using Recreate = Component<NoData, class RecreateTag>;
IGN_GAZEBO_REGISTER_COMPONENT("ign_gazebo_components.Recreate", Recreate)
}
}
}
}

#endif
4 changes: 4 additions & 0 deletions include/ignition/gazebo/detail/View.hh
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,10 @@ template<typename ...ComponentTypeTs>
bool View<ComponentTypeTs...>::NotifyComponentRemoval(const Entity _entity,
const ComponentTypeId _typeId)
{
// if entity is still marked as to add, remove from the view
if (this->RequiresComponent(_typeId))
this->toAddEntities.erase(_entity);

// make sure that _typeId is a type required by the view and that _entity is
// already a part of the view
if (!this->RequiresComponent(_typeId) ||
Expand Down
43 changes: 41 additions & 2 deletions src/EntityComponentManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "ignition/gazebo/components/Name.hh"
#include "ignition/gazebo/components/ParentEntity.hh"
#include "ignition/gazebo/components/ParentLinkName.hh"
#include "ignition/gazebo/components/Recreate.hh"

using namespace ignition;
using namespace gazebo;
Expand Down Expand Up @@ -420,7 +421,30 @@ Entity EntityComponentManager::CloneImpl(Entity _entity, Entity _parent,
}
else if (!_name.empty() && !_allowRename)
{
if (kNullEntity != this->EntityByComponents(components::Name(_name)))
// Get the entity's original parent. This is used to make sure we get
// the correct entity. For example, two different models may have a
// child with the name "link".
auto origParentComp =
this->Component<components::ParentEntity>(_entity);

// If there is an entity with the same name and user indicated renaming is
// not allowed then return null entity.
// If the entity or one of its ancestor has a Recreate component then carry
// on since the ECM is supposed to create a new entity with the same name.
Entity ent = this->EntityByComponents(components::Name(_name),
components::ParentEntity(origParentComp->Data()));

bool hasRecreateComp = false;
Entity recreateEnt = ent;
while (recreateEnt != kNullEntity && !hasRecreateComp)
{
hasRecreateComp = this->Component<components::Recreate>(recreateEnt) !=
nullptr;
auto parentComp = this->Component<components::ParentEntity>(recreateEnt);
recreateEnt = parentComp ? parentComp->Data() : kNullEntity;
}

if (kNullEntity != ent && !hasRecreateComp)
{
ignerr << "Requested to clone entity [" << _entity
<< "] with a name of [" << _name << "], but another entity already "
Expand Down Expand Up @@ -533,7 +557,14 @@ Entity EntityComponentManager::CloneImpl(Entity _entity, Entity _parent,
for (const auto &childEntity :
this->EntitiesByComponents(components::ParentEntity(_entity)))
{
auto clonedChild = this->CloneImpl(childEntity, clonedEntity, "", true);
std::string name;
if (!_allowRename)
{
auto nameComp = this->Component<components::Name>(childEntity);
name = nameComp->Data();
}
auto clonedChild = this->CloneImpl(childEntity, clonedEntity, name,
_allowRename);
if (kNullEntity == clonedChild)
{
ignerr << "Cloning child entity [" << childEntity << "] failed.\n";
Expand Down Expand Up @@ -1038,6 +1069,14 @@ bool EntityComponentManager::CreateComponentImplementation(

this->dataPtr->createdCompTypes.insert(_componentTypeId);

// If the component is a components::ParentEntity, then make sure to
// update the entities graph.
if (_componentTypeId == components::ParentEntity::typeId)
{
auto parentComp = this->Component<components::ParentEntity>(_entity);
this->SetParentEntity(_entity, parentComp->Data());
}

return updateData;
}

Expand Down
97 changes: 92 additions & 5 deletions src/SimulationRunner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
#include "ignition/gazebo/components/Sensor.hh"
#include "ignition/gazebo/components/Visual.hh"
#include "ignition/gazebo/components/World.hh"
#include "ignition/gazebo/components/ParentEntity.hh"
#include "ignition/gazebo/components/Physics.hh"
#include "ignition/gazebo/components/PhysicsCmd.hh"
#include "ignition/gazebo/components/Recreate.hh"
#include "ignition/gazebo/Events.hh"
#include "ignition/gazebo/SdfEntityCreator.hh"
#include "ignition/gazebo/Util.hh"
Expand Down Expand Up @@ -820,6 +822,10 @@ void SimulationRunner::Step(const UpdateInfo &_info)
IGN_PROFILE("SimulationRunner::Step");
this->currentInfo = _info;

// Process new ECM state information, typically sent from the GUI after
// a change was made to the GUI's ECM.
this->ProcessNewWorldControlState();

// Publish info
this->PublishStats();

Expand All @@ -831,6 +837,12 @@ void SimulationRunner::Step(const UpdateInfo &_info)
// Handle pending systems
this->ProcessSystemQueue();

// Handle entities that need to be recreated.
// Put in a request to mark them as removed so that in the UpdateSystem call
// the systems can remove them first before new ones are created. This is
// so that we can recreate entities with the same name.
this->ProcessRecreateEntitiesRemove();

// Update all the systems.
this->UpdateSystems();

Expand Down Expand Up @@ -861,6 +873,12 @@ void SimulationRunner::Step(const UpdateInfo &_info)
// Clear all new entities
this->entityCompMgr.ClearNewlyCreatedEntities();

// Recreate any entities that have the Recreate component
// The entities will have different Entity ids but keep the same name
// Make sure this happens after ClearNewlyCreatedEntities, otherwise the
// cloned entities will loose their "New" state.
this->ProcessRecreateEntitiesCreate();

// Process entity removals.
this->entityCompMgr.ProcessRemoveEntityRequests();

Expand Down Expand Up @@ -1136,11 +1154,13 @@ bool SimulationRunner::OnWorldControlState(const msgs::WorldControlState &_req,
{
std::lock_guard<std::mutex> lock(this->msgBufferMutex);

// update the server ECM if the request contains SerializedState information
// Copy the state information if it exists
if (_req.has_state())
this->entityCompMgr.SetState(_req.state());
// TODO(anyone) notify server systems of changes made to the ECM, if there
// were any?
{
if (this->newWorldControlState == nullptr)
this->newWorldControlState = _req.New();
this->newWorldControlState->CopyFrom(_req);
}

WorldControl control;
control.pause = _req.world_control().pause();
Expand Down Expand Up @@ -1170,7 +1190,7 @@ bool SimulationRunner::OnWorldControlState(const msgs::WorldControlState &_req,
{
control.runToSimTime = std::chrono::seconds(
_req.world_control().run_to_sim_time().sec()) +
std::chrono::nanoseconds(_req.world_control().run_to_sim_time().nsec());
std::chrono::nanoseconds(_req.world_control().run_to_sim_time().nsec());
}

this->worldControls.push_back(control);
Expand All @@ -1179,6 +1199,22 @@ bool SimulationRunner::OnWorldControlState(const msgs::WorldControlState &_req,
return true;
}

/////////////////////////////////////////////////
void SimulationRunner::ProcessNewWorldControlState()
{
std::lock_guard<std::mutex> lock(this->msgBufferMutex);
// update the server ECM if the request contains SerializedState information
if (this->newWorldControlState && this->newWorldControlState->has_state())
{
this->entityCompMgr.SetState(this->newWorldControlState->state());

delete this->newWorldControlState;
this->newWorldControlState = nullptr;
}
// TODO(anyone) notify server systems of changes made to the ECM, if there
// were any?
}

/////////////////////////////////////////////////
bool SimulationRunner::OnPlaybackControl(const msgs::LogPlaybackControl &_req,
msgs::Boolean &_res)
Expand Down Expand Up @@ -1252,6 +1288,57 @@ void SimulationRunner::ProcessWorldControl()
this->worldControls.clear();
}

/////////////////////////////////////////////////
void SimulationRunner::ProcessRecreateEntitiesRemove()
{
IGN_PROFILE("SimulationRunner::ProcessRecreateEntitiesRemove");

// store the original entities to recreate and put in request to remove them
this->entityCompMgr.Each<components::Model,
components::Recreate>(
[&](const Entity &_entity,
const components::Model *,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only models are being removed, can we document this? Maybe on the component?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added documentation in 14d78f3

const components::Recreate *)->bool
{
this->entitiesToRecreate.insert(_entity);
this->entityCompMgr.RequestRemoveEntity(_entity, true);
return true;
});
}

/////////////////////////////////////////////////
void SimulationRunner::ProcessRecreateEntitiesCreate()
{
IGN_PROFILE("SimulationRunner::ProcessRecreateEntitiesCreate");

// clone the original entities
std::set<Entity> entitiesToRemoveRecreateComp;
for (auto & ent : this->entitiesToRecreate)
{
auto nameComp = this->entityCompMgr.Component<components::Name>(ent);
auto parentComp =
this->entityCompMgr.Component<components::ParentEntity>(ent);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's safer to check that the entity indeed has a name and a parent. At ProcessRecreateEntitiesRemove we're limiting the functionality to models, so it's usually safe to assume these components are present. But we can't be always sure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added checks in 14d78f3

// set allowRenaming to false so the entities keep their original name
Entity clonedEntity = this->entityCompMgr.Clone(ent,
parentComp->Data(), nameComp->Data(), false);
entitiesToRemoveRecreateComp.insert(clonedEntity);
entitiesToRemoveRecreateComp.insert(ent);
}

// remove the Recreate component so they do not get recreated again in the
// next iteration
for (auto &ent : entitiesToRemoveRecreateComp)
{
if (!this->entityCompMgr.RemoveComponent<components::Recreate>(ent))
{
ignerr << "Failed to remove Recreate component from entity["
<< ent << "]" << std::endl;
}
}

this->entitiesToRecreate.clear();
}

/////////////////////////////////////////////////
bool SimulationRunner::Paused() const
{
Expand Down
20 changes: 20 additions & 0 deletions src/SimulationRunner.hh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <list>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <unordered_set>
Expand Down Expand Up @@ -466,6 +467,18 @@ namespace ignition
std::optional<Entity> _entity = std::nullopt,
std::optional<std::shared_ptr<const sdf::Element>> _sdf = std::nullopt);

/// \brief Process entities with the components::Recreate component.
/// Put in a request to make them as removed
private: void ProcessRecreateEntitiesRemove();

/// \brief Process entities with the components::Recreate component.
/// Reccreate the entities by cloning from the original ones.
private: void ProcessRecreateEntitiesCreate();

/// \brief Process the new world state message, if it is present.
/// See the newWorldControlState variable below.
private: void ProcessNewWorldControlState();

/// \brief This is used to indicate that a stop event has been received.
private: std::atomic<bool> stopReceived{false};

Expand Down Expand Up @@ -627,6 +640,13 @@ namespace ignition
/// WorldControl info (true) or not (false)
private: bool stepping{false};

/// \brief A set of entities that need to be recreated
private: std::set<Entity> entitiesToRecreate;

/// \brief Holds new world state information so that it can processed
/// at the appropriate time.
private: msgs::WorldControlState *newWorldControlState{nullptr};

friend class LevelManager;
};
}
Expand Down
1 change: 1 addition & 0 deletions src/SimulationRunner_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
#include "ignition/gazebo/Events.hh"
#include "ignition/gazebo/Util.hh"
#include "ignition/gazebo/config.hh"

#include "../test/helpers/EnvTestFixture.hh"
#include "SimulationRunner.hh"

Expand Down
1 change: 1 addition & 0 deletions src/gui/plugins/component_inspector/ComponentInspector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <iostream>
#include <list>
#include <regex>

#include <ignition/common/Console.hh>
#include <ignition/common/MeshManager.hh>
#include <ignition/common/Profiler.hh>
Expand Down
1 change: 0 additions & 1 deletion src/gui/plugins/component_inspector/ComponentInspector.hh
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ namespace gazebo
<< _item->text().toStdString() << "]" << std::endl;
}
}

/// \brief Specialized to set string data.
/// \param[in] _item Item whose data will be set.
/// \param[in] _data Data to set.
Expand Down
4 changes: 4 additions & 0 deletions src/gui/plugins/component_inspector/ModelEditor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "ignition/gazebo/components/Model.hh"
#include "ignition/gazebo/components/Name.hh"
#include "ignition/gazebo/components/ParentEntity.hh"
#include "ignition/gazebo/components/Recreate.hh"
#include "ignition/gazebo/EntityComponentManager.hh"
#include "ignition/gazebo/SdfEntityCreator.hh"

Expand Down Expand Up @@ -181,6 +182,9 @@ void ModelEditor::Update(const UpdateInfo &,
linkSdf.SetName(linkName);
auto entity = this->dataPtr->entityCreator->CreateEntities(&linkSdf);
this->dataPtr->entityCreator->SetParent(entity, eta.parentEntity);
// Make sure to mark the parent as needing recreation. This will
// tell the server to rebuild the model with the new link.
_ecm.CreateComponent(eta.parentEntity, components::Recreate());

// traverse the tree and add all new entities created by the entity
// creator to the set
Expand Down
Loading