diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index cf70ca6852..705db4f35d 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,13 +14,12 @@ jobs:
uses: ignition-tooling/action-ignition-ci@bionic
with:
codecov-token: ${{ secrets.CODECOV_TOKEN }}
- # TODO(anyone) Enable Focal CI and fix failing tests
- # focal-ci:
- # runs-on: ubuntu-latest
- # name: Ubuntu Focal CI
- # steps:
- # - name: Checkout
- # uses: actions/checkout@v2
- # - name: Compile and test
- # id: ci
- # uses: ignition-tooling/action-ignition-ci@focal
+ focal-ci:
+ runs-on: ubuntu-latest
+ name: Ubuntu Focal CI
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ - name: Compile and test
+ id: ci
+ uses: ignition-tooling/action-ignition-ci@focal
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fc229248f..d199fe7b17 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -87,7 +87,7 @@ ign_find_package (Qt5
#--------------------------------------
# Find ignition-physics
-ign_find_package(ignition-physics3 VERSION 3.1
+ign_find_package(ignition-physics3 VERSION 3.2
COMPONENTS
mesh
sdf
diff --git a/examples/worlds/pendulum_links.sdf b/examples/worlds/pendulum_links.sdf
new file mode 100644
index 0000000000..2f62bab25c
--- /dev/null
+++ b/examples/worlds/pendulum_links.sdf
@@ -0,0 +1,279 @@
+
+
+
+
+
+
+
+ 0.001
+ 1.0
+
+
+
+
+
+
+
+
+
+ true
+ 0 0 10 0 0 0
+ 0.8 0.8 0.8 1
+ 0.2 0.2 0.2 1
+
+ 1000
+ 0.9
+ 0.01
+ 0.001
+
+ -0.5 0.1 -0.9
+
+
+
+ true
+
+
+
+
+ 0 0 1
+
+
+
+
+
+
+ 0 0 1
+ 100 100
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+
+
+
+
+
+
+ 100
+
+
+ 0 0 0.01 0 0 0
+
+
+ 0.8
+ 0.02
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+
+ -0.275 0 1.1 0 0 0
+
+
+ 0.2 0.2 2.2
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+
+ 0 0 0.01 0 0 0
+
+
+ 0.8
+ 0.02
+
+
+
+
+ -0.275 0 1.1 0 0 0
+
+
+ 0.2 0.2 2.2
+
+
+
+
+
+
+ 0 0 2.1 -1.5708 0 0
+ 0
+
+ 0 0 0.5 0 0 0
+
+
+ -0.05 0 0 0 1.5708 0
+
+
+ 0.1
+ 0.3
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+
+ 0 0 1.0 0 1.5708 0
+
+
+ 0.1
+ 0.2
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+
+ 0 0 0.5 0 0 0
+
+
+ 0.1
+ 0.9
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+
+ -0.05 0 0 0 1.5708 0
+
+
+ 0.1
+ 0.3
+
+
+
+
+ 0 0 1.0 0 1.5708 0
+
+
+ 0.1
+ 0.2
+
+
+
+
+ 0 0 0.5 0 0 0
+
+
+ 0.1
+ 0.9
+
+
+
+
+
+
+ 0.25 1.0 2.1 -2 0 0
+ 0
+
+ 0 0 0.5 0 0 0
+
+
+ 0 0 0 0 1.5708 0
+
+
+ 0.08
+ 0.3
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+
+ 0 0 0.5 0 0 0
+
+
+ 0.1
+ 0.9
+
+
+
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+ 0.8 0.8 0.8 1
+
+
+
+ 0 0 0 0 1.5708 0
+
+
+ 0.08
+ 0.3
+
+
+
+
+ 0 0 0.5 0 0 0
+
+
+ 0.1
+ 0.9
+
+
+
+
+
+
+ base
+ upper_link
+
+ 1.0 0 0
+
+
+
+
+ upper_link
+ lower_link
+
+ 1.0 0 0
+
+
+
+
+ base
+ upper_link
+ lower_link
+
+
+
+
diff --git a/src/EntityComponentManager.cc b/src/EntityComponentManager.cc
index acb11faaf9..c6c32e595b 100644
--- a/src/EntityComponentManager.cc
+++ b/src/EntityComponentManager.cc
@@ -117,7 +117,7 @@ class ignition::gazebo::EntityComponentManagerPrivate
/// NOTE: Any modification of this data structure must be followed
/// by setting `entityComponentsDirty` to true.
public: std::unordered_map> entityComponents;
+ std::unordered_map> entityComponents;
/// \brief A vector of iterators to evenly distributed spots in the
/// `entityComponents` map. Threads in the `State` function use this
@@ -125,7 +125,7 @@ class ignition::gazebo::EntityComponentManagerPrivate
/// is recalculated if `entityComponents` is changed (when
/// `entityComponentsDirty` == true).
public: std::vector>::iterator>
+ std::unordered_map>::iterator>
entityComponentIterators;
/// \brief A mutex to protect newly created entities.
@@ -317,8 +317,7 @@ void EntityComponentManager::ProcessRemoveEntityRequests()
{
for (const auto &key : entityIter->second)
{
- this->dataPtr->components.at(key.second.first)->Remove(
- key.second.second);
+ this->dataPtr->components.at(key.first)->Remove(key.second);
}
// Remove the entry in the entityComponent map
@@ -438,12 +437,14 @@ ComponentState EntityComponentManager::ComponentState(const Entity _entity,
if (typeKey == ecIter->second.end())
return result;
- if (this->dataPtr->oneTimeChangedComponents.find(typeKey->second) !=
+ ComponentKey key{_typeId, typeKey->second};
+
+ if (this->dataPtr->oneTimeChangedComponents.find(key) !=
this->dataPtr->oneTimeChangedComponents.end())
{
result = ComponentState::OneTimeChange;
}
- else if (this->dataPtr->periodicChangedComponents.find(typeKey->second) !=
+ else if (this->dataPtr->periodicChangedComponents.find(key) !=
this->dataPtr->periodicChangedComponents.end())
{
result = ComponentState::PeriodicChange;
@@ -552,7 +553,7 @@ ComponentKey EntityComponentManager::CreateComponentImplementation(
ComponentKey componentKey{_componentTypeId, componentIdPair.first};
this->dataPtr->entityComponents[_entity].insert(
- {_componentTypeId, componentKey});
+ {_componentTypeId, componentIdPair.first});
this->dataPtr->oneTimeChangedComponents.insert(componentKey);
this->dataPtr->entityComponentsDirty = true;
@@ -597,7 +598,7 @@ ComponentId EntityComponentManager::EntityComponentIdFromType(
auto typeIter = ecIter->second.find(_type);
if (typeIter != ecIter->second.end())
- return typeIter->second.second;
+ return typeIter->second;
return -1;
}
@@ -615,8 +616,8 @@ const components::BaseComponent
auto typeIter = ecIter->second.find(_type);
if (typeIter != ecIter->second.end())
- return this->dataPtr->components.at(typeIter->second.first)->Component(
- typeIter->second.second);
+ return this->dataPtr->components.at(_type)->Component(
+ typeIter->second);
return nullptr;
}
@@ -632,8 +633,7 @@ components::BaseComponent *EntityComponentManager::ComponentImplementation(
auto typeIter = ecIter->second.find(_type);
if (typeIter != ecIter->second.end())
- return this->dataPtr->components.at(typeIter->second.first)->Component(
- typeIter->second.second);
+ return this->dataPtr->components.at(_type)->Component(typeIter->second);
return nullptr;
}
@@ -895,16 +895,14 @@ void EntityComponentManager::AddEntityToMessage(msgs::SerializedState &_msg,
for (const ComponentTypeId type : types)
{
// If the entity does not have the component, continue
- std::unordered_map::iterator typeIter =
- iter->second.find(type);
+ auto typeIter = iter->second.find(type);
if (typeIter == iter->second.end())
{
continue;
}
- ComponentKey comp = (typeIter->second);
auto compMsg = entityMsg->add_components();
- auto compBase = this->ComponentImplementation(_entity, comp.first);
+ auto compBase = this->ComponentImplementation(_entity, type);
compMsg->set_type(compBase->TypeId());
std::ostringstream ostr;
@@ -962,16 +960,16 @@ void EntityComponentManager::AddEntityToMessage(msgs::SerializedStateMap &_msg,
// Empty means all types
for (const ComponentTypeId type : types)
{
- std::unordered_map::iterator typeIter =
- iter->second.find(type);
+ auto typeIter = iter->second.find(type);
if (typeIter == iter->second.end())
{
continue;
}
- ComponentKey comp = typeIter->second;
const components::BaseComponent *compBase =
- this->ComponentImplementation(_entity, comp.first);
+ this->ComponentImplementation(_entity, type);
+
+ ComponentKey comp = {type, typeIter->second};
// If not sending full state, skip unchanged components
if (!_full &&
@@ -1447,20 +1445,22 @@ void EntityComponentManager::SetChanged(
if (typeIter == ecIter->second.end())
return;
+ ComponentKey key{_type, typeIter->second};
+
if (_c == ComponentState::PeriodicChange)
{
- this->dataPtr->periodicChangedComponents.insert(typeIter->second);
- this->dataPtr->oneTimeChangedComponents.erase(typeIter->second);
+ this->dataPtr->periodicChangedComponents.insert(key);
+ this->dataPtr->oneTimeChangedComponents.erase(key);
}
else if (_c == ComponentState::OneTimeChange)
{
- this->dataPtr->periodicChangedComponents.erase(typeIter->second);
- this->dataPtr->oneTimeChangedComponents.insert(typeIter->second);
+ this->dataPtr->periodicChangedComponents.erase(key);
+ this->dataPtr->oneTimeChangedComponents.insert(key);
}
else
{
- this->dataPtr->periodicChangedComponents.erase(typeIter->second);
- this->dataPtr->oneTimeChangedComponents.erase(typeIter->second);
+ this->dataPtr->periodicChangedComponents.erase(key);
+ this->dataPtr->oneTimeChangedComponents.erase(key);
}
this->dataPtr->AddModifiedComponent(_entity);
diff --git a/src/EntityComponentManager_TEST.cc b/src/EntityComponentManager_TEST.cc
index 04e9b86a25..e22a4ce5c2 100644
--- a/src/EntityComponentManager_TEST.cc
+++ b/src/EntityComponentManager_TEST.cc
@@ -2255,6 +2255,11 @@ TEST_P(EntityComponentManagerFixture, SetEntityCreateOffset)
manager.SetEntityCreateOffset(1000);
Entity entity2 = manager.CreateEntity();
EXPECT_EQ(1001u, entity2);
+
+ // Apply a lower offset, prints warning but goes through.
+ manager.SetEntityCreateOffset(500);
+ Entity entity3 = manager.CreateEntity();
+ EXPECT_EQ(501u, entity3);
}
//////////////////////////////////////////////////
diff --git a/src/systems/physics/Physics.cc b/src/systems/physics/Physics.cc
index 5a3daf3357..50ce67f4bf 100644
--- a/src/systems/physics/Physics.cc
+++ b/src/systems/physics/Physics.cc
@@ -1609,6 +1609,111 @@ void PhysicsPrivate::UpdatePhysics(EntityComponentManager &_ecm)
return true;
});
+ // Update link angular velocity
+ _ecm.Each(
+ [&](const Entity &_entity, const components::Link *,
+ const components::AngularVelocityCmd *_angularVelocityCmd)
+ {
+ if (!this->entityLinkMap.HasEntity(_entity))
+ {
+ ignwarn << "Failed to find link [" << _entity
+ << "]." << std::endl;
+ return true;
+ }
+
+ auto linkPtrPhys = this->entityLinkMap.Get(_entity);
+ if (nullptr == linkPtrPhys)
+ return true;
+
+ auto freeGroup = linkPtrPhys->FindFreeGroup();
+ if (!freeGroup)
+ return true;
+ this->entityFreeGroupMap.AddEntity(_entity, freeGroup);
+
+ auto worldAngularVelFeature =
+ this->entityFreeGroupMap
+ .EntityCast(_entity);
+
+ if (!worldAngularVelFeature)
+ {
+ static bool informed{false};
+ if (!informed)
+ {
+ igndbg << "Attempting to set link angular velocity, but the "
+ << "physics engine doesn't support velocity commands. "
+ << "Velocity won't be set."
+ << std::endl;
+ informed = true;
+ }
+ return true;
+ }
+ // velocity in world frame = world_to_model_tf * model_to_link_tf * vel
+ Entity modelEntity = topLevelModel(_entity, _ecm);
+ const components::Pose *modelEntityPoseComp =
+ _ecm.Component(modelEntity);
+ math::Pose3d modelToLinkTransform = this->RelativePose(
+ modelEntity, _entity, _ecm);
+ math::Vector3d worldAngularVel = modelEntityPoseComp->Data().Rot()
+ * modelToLinkTransform.Rot() * _angularVelocityCmd->Data();
+ worldAngularVelFeature->SetWorldAngularVelocity(
+ math::eigen3::convert(worldAngularVel));
+
+ return true;
+ });
+
+ // Update link linear velocity
+ _ecm.Each(
+ [&](const Entity &_entity, const components::Link *,
+ const components::LinearVelocityCmd *_linearVelocityCmd)
+ {
+ if (!this->entityLinkMap.HasEntity(_entity))
+ {
+ ignwarn << "Failed to find link [" << _entity
+ << "]." << std::endl;
+ return true;
+ }
+
+ auto linkPtrPhys = this->entityLinkMap.Get(_entity);
+ if (nullptr == linkPtrPhys)
+ return true;
+
+ auto freeGroup = linkPtrPhys->FindFreeGroup();
+ if (!freeGroup)
+ return true;
+ this->entityFreeGroupMap.AddEntity(_entity, freeGroup);
+
+ auto worldLinearVelFeature =
+ this->entityFreeGroupMap
+ .EntityCast(_entity);
+ if (!worldLinearVelFeature)
+ {
+ static bool informed{false};
+ if (!informed)
+ {
+ igndbg << "Attempting to set link linear velocity, but the "
+ << "physics engine doesn't support velocity commands. "
+ << "Velocity won't be set."
+ << std::endl;
+ informed = true;
+ }
+ return true;
+ }
+
+ // velocity in world frame = world_to_model_tf * model_to_link_tf * vel
+ Entity modelEntity = topLevelModel(_entity, _ecm);
+ const components::Pose *modelEntityPoseComp =
+ _ecm.Component(modelEntity);
+ math::Pose3d modelToLinkTransform = this->RelativePose(
+ modelEntity, _entity, _ecm);
+ math::Vector3d worldLinearVel = modelEntityPoseComp->Data().Rot()
+ * modelToLinkTransform.Rot() * _linearVelocityCmd->Data();
+ worldLinearVelFeature->SetWorldLinearVelocity(
+ math::eigen3::convert(worldLinearVel));
+
+ return true;
+ });
+
+
// Populate bounding box info
// Only compute bounding box if component exists to avoid unnecessary
// computations
@@ -2095,6 +2200,20 @@ void PhysicsPrivate::UpdateSim(EntityComponentManager &_ecm)
});
IGN_PROFILE_END();
+ _ecm.Each(
+ [&](const Entity &, components::AngularVelocityCmd *_vel) -> bool
+ {
+ _vel->Data() = math::Vector3d::Zero;
+ return true;
+ });
+
+ _ecm.Each(
+ [&](const Entity &, components::LinearVelocityCmd *_vel) -> bool
+ {
+ _vel->Data() = math::Vector3d::Zero;
+ return true;
+ });
+
// Update joint positions
IGN_PROFILE_BEGIN("Joints");
_ecm.Each(
diff --git a/src/systems/velocity_control/VelocityControl.cc b/src/systems/velocity_control/VelocityControl.cc
index 78b1913d67..a645ebe0cf 100644
--- a/src/systems/velocity_control/VelocityControl.cc
+++ b/src/systems/velocity_control/VelocityControl.cc
@@ -15,9 +15,11 @@
*
*/
+#include