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

ECM's ChangedState gets message with modified components #742

Merged
merged 6 commits into from
Apr 9, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
8 changes: 2 additions & 6 deletions include/ignition/gazebo/EntityComponentManager.hh
Original file line number Diff line number Diff line change
Expand Up @@ -474,11 +474,9 @@ namespace ignition
/// \brief Get a message with the serialized state of all entities and
/// components that are changing in the current iteration
///
/// Currently supported:
/// This includes:
/// * New entities and all of their components
/// * Removed entities and all of their components
///
/// Future work:
/// * Entities which had a component added
/// * Entities which had a component removed
/// * Entities which had a component modified
Expand Down Expand Up @@ -535,11 +533,9 @@ namespace ignition
/// \brief Get a message with the serialized state of all entities and
/// components that are changing in the current iteration
///
/// Currently supported:
/// This includes:
/// * New entities and all of their components
/// * Removed entities and all of their components
///
/// Future work:
/// * Entities which had a component added
/// * Entities which had a component removed
/// * Entities which had a component modified
Expand Down
49 changes: 47 additions & 2 deletions src/EntityComponentManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ class ignition::gazebo::EntityComponentManagerPrivate
msgs::SerializedStateMap &_msg,
const std::unordered_set<ComponentTypeId> &_types = {});

/// \brief Add newly modified (created/modified/removed) components to
/// modifiedComponents list. The entity is added to the list when it is not
/// a newly created entity or is not an entity to be removed
/// \param[in] _entity Entity that has component newly modified
public: void AddModifiedComponent(const Entity &_entity);

/// \brief Map of component storage classes. The key is a component
/// type id, and the value is a pointer to the component storage.
public: std::unordered_map<ComponentTypeId,
Expand All @@ -93,6 +99,12 @@ class ignition::gazebo::EntityComponentManagerPrivate
/// \brief Entities that need to be removed.
public: std::unordered_set<Entity> toRemoveEntities;

/// \brief Entities that have components newly modified
/// (created/modified/removed) but are not entities that have been
/// newly created or removed (ie. newlyCreatedEntities or toRemoveEntities).
/// This is used for the ChangedState functions
public: std::unordered_set<Entity> modifiedComponents;

/// \brief Flag that indicates if all entities should be removed.
public: bool removeAllEntities{false};

Expand Down Expand Up @@ -199,6 +211,7 @@ void EntityComponentManager::ClearNewlyCreatedEntities()
{
std::lock_guard<std::mutex> lock(this->dataPtr->entityCreatedMutex);
this->dataPtr->newlyCreatedEntities.clear();
this->dataPtr->modifiedComponents.clear();
Copy link
Contributor

Choose a reason for hiding this comment

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

should this call be in ClearNewlyCreatedEntities or maybe it fits better in SetAllComponentsUnchanged?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to SetAllComponentsUnchanged 70c4320


for (auto &view : this->dataPtr->views)
{
Expand Down Expand Up @@ -354,6 +367,8 @@ bool EntityComponentManager::RemoveComponent(

this->UpdateViews(_entity);

this->dataPtr->AddModifiedComponent(_entity);

// Add component to map of removed components
{
std::lock_guard<std::mutex> lock(this->dataPtr->removedComponentsMutex);
Expand Down Expand Up @@ -529,6 +544,8 @@ ComponentKey EntityComponentManager::CreateComponentImplementation(
}
}

this->dataPtr->AddModifiedComponent(_entity);

// Instantiate the new component.
std::pair<ComponentId, bool> componentIdPair =
this->dataPtr->components[_componentTypeId]->Create(_data);
Expand Down Expand Up @@ -1021,7 +1038,11 @@ ignition::msgs::SerializedState EntityComponentManager::ChangedState() const
this->AddEntityToMessage(stateMsg, entity);
}

// TODO(anyone) New / removed / changed components
// New / removed / changed components
for (const auto &entity : this->dataPtr->modifiedComponents)
{
this->AddEntityToMessage(stateMsg, entity);
}

return stateMsg;
}
Expand All @@ -1042,7 +1063,11 @@ void EntityComponentManager::ChangedState(
this->AddEntityToMessage(_state, entity);
}

// TODO(anyone) New / removed / changed components
// New / removed / changed components
for (const auto &entity : this->dataPtr->modifiedComponents)
{
this->AddEntityToMessage(_state, entity);
}
}

//////////////////////////////////////////////////
Expand Down Expand Up @@ -1257,6 +1282,7 @@ void EntityComponentManager::SetState(
// values.
// igndbg << *comp << " " << *newComp.get() << std::endl;
// *comp = *newComp.get();
this->dataPtr->AddModifiedComponent(entity);
Copy link
Contributor

Choose a reason for hiding this comment

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

is this call needed here? Given that the above msg says internal error, I expect that something is wrong is it gets to this else block. Looking at the code, the component value is just being updated by removing the old component and creating a new one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not needed currently but I put the call there in case the above TODO is addressed. Should I comment it out with a note to add it in when the TODO is addressed and if SetChanged is not called?

Copy link
Contributor

Choose a reason for hiding this comment

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

I see, yeah you can comment it out and add a note here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done 70c4320

}
}
}
Expand Down Expand Up @@ -1367,6 +1393,7 @@ void EntityComponentManager::SetState(
}
}
this->SetChanged(entity, compIter.first, flag);
this->dataPtr->AddModifiedComponent(entity);
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 the SetChanged call above will also call AddModifiedComponent

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops, thanks 70c4320

}
}
}
Expand Down Expand Up @@ -1433,6 +1460,8 @@ void EntityComponentManager::SetChanged(
this->dataPtr->periodicChangedComponents.erase(typeIter->second);
this->dataPtr->oneTimeChangedComponents.erase(typeIter->second);
}

this->dataPtr->AddModifiedComponent(_entity);
}

/////////////////////////////////////////////////
Expand Down Expand Up @@ -1465,3 +1494,19 @@ void EntityComponentManager::SetEntityCreateOffset(uint64_t _offset)

this->dataPtr->entityCount = _offset;
}

/////////////////////////////////////////////////
void EntityComponentManagerPrivate::AddModifiedComponent(const Entity &_entity)
{
if (this->newlyCreatedEntities.find(_entity)
!= this->newlyCreatedEntities.end() ||
this->toRemoveEntities.find(_entity) != this->toRemoveEntities.end() ||
this->modifiedComponents.find(_entity) != this->modifiedComponents.end())
{
// modified component is already in newlyCreatedEntities
// or toRemoveEntities list
return;
}

this->modifiedComponents.insert(_entity);
}
70 changes: 69 additions & 1 deletion src/EntityComponentManager_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1805,7 +1805,7 @@ TEST_P(EntityComponentManagerFixture, State)
{
// Check the changed state
auto changedStateMsg = manager.ChangedState();
EXPECT_EQ(2, changedStateMsg.entities_size());
EXPECT_EQ(4, changedStateMsg.entities_size());

const auto &e4Msg = changedStateMsg.entities(0);
EXPECT_EQ(e4, e4Msg.id());
Expand Down Expand Up @@ -1887,6 +1887,74 @@ TEST_P(EntityComponentManagerFixture, State)
}
}

/////////////////////////////////////////////////
TEST_P(EntityComponentManagerFixture, ChangedStateComponents)
{
// Entity and component
Entity e1{1};
int e1c0{123};
std::string e1c1{"string"};

// Fill manager with entity
EXPECT_EQ(e1, manager.CreateEntity());
EXPECT_EQ(1u, manager.EntityCount());

// Component
manager.CreateComponent<IntComponent>(e1, IntComponent(e1c0));

// Serialize into a message
msgs::SerializedStateMap stateMsg;
manager.State(stateMsg);
ASSERT_EQ(1, stateMsg.entities_size());

// Mark entities/components as not new
manager.RunClearNewlyCreatedEntities();
auto changedStateMsg = manager.ChangedState();
EXPECT_EQ(0, changedStateMsg.entities_size());

// create component
auto compKey =
manager.CreateComponent<StringComponent>(e1, StringComponent(e1c1));
changedStateMsg = manager.ChangedState();
EXPECT_EQ(1, changedStateMsg.entities_size());

// Mark entities/components as not new
manager.RunClearNewlyCreatedEntities();
changedStateMsg = manager.ChangedState();
EXPECT_EQ(0, changedStateMsg.entities_size());

// modify component
manager.State(stateMsg);
auto iter = stateMsg.mutable_entities()->find(e1);
ASSERT_TRUE(iter != stateMsg.mutable_entities()->end());

msgs::SerializedEntityMap &e1Msg = iter->second;

auto compIter = e1Msg.mutable_components()->find(compKey.first);
ASSERT_TRUE(compIter != e1Msg.mutable_components()->end());

msgs::SerializedComponent &e1c1Msg = compIter->second;
EXPECT_EQ(e1c1, e1c1Msg.component());
e1c1Msg.set_component("test");
EXPECT_EQ("test", e1c1Msg.component());
(*e1Msg.mutable_components())[e1c1Msg.type()] = e1c1Msg;

manager.SetState(stateMsg);
changedStateMsg = manager.ChangedState();
EXPECT_EQ(1, changedStateMsg.entities_size());

// Mark entities/components as not new
manager.RunClearNewlyCreatedEntities();
changedStateMsg = manager.ChangedState();
EXPECT_EQ(0, changedStateMsg.entities_size());

// remove component
manager.RemoveComponent(e1, StringComponent::typeId);

changedStateMsg = manager.ChangedState();
EXPECT_EQ(1, changedStateMsg.entities_size());
}

/////////////////////////////////////////////////
TEST_P(EntityComponentManagerFixture, Descendants)
{
Expand Down
22 changes: 21 additions & 1 deletion test/integration/log_system.cc
Original file line number Diff line number Diff line change
Expand Up @@ -780,7 +780,27 @@ TEST_F(LogSystemTest, RecordAndPlayback)
stateMsg.ParseFromString(recordedIter->Data());
// entity size = 28 in dbl pendulum + 4 in nested model
EXPECT_EQ(32, stateMsg.entities_size());
EXPECT_EQ(batch.end(), ++recordedIter);
EXPECT_NE(batch.end(), ++recordedIter);

// check rest of recordIter (state message) for poses
while (batch.end() != recordedIter)
{
EXPECT_EQ("ignition.msgs.SerializedStateMap", recordedIter->Type());
EXPECT_EQ(recordedIter->Topic(), "/world/log_pendulum/changed_state");

stateMsg.ParseFromString(recordedIter->Data());

for (const auto &entityIter : stateMsg.entities())
{
for (const auto &compIter : entityIter.second.components())
{
EXPECT_EQ(components::Pose::typeId, compIter.second.type());
}
}
++recordedIter;
}

EXPECT_EQ(batch.end(), recordedIter);

// Keep track of total number of pose comparisons
int nTotal{0};
Expand Down