ROS2FrameComponent.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include "ROS2/Frame/ROS2FrameComponent.h"
  9. #include "ROS2/ROS2Bus.h"
  10. #include "ROS2/Utilities/ROS2Names.h"
  11. #include <AzCore/Component/Entity.h>
  12. #include <AzCore/Serialization/EditContext.h>
  13. #include <AzCore/Serialization/EditContextConstants.inl>
  14. #include <AzCore/Serialization/SerializeContext.h>
  15. #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
  16. #include <AzToolsFramework/ToolsComponents/TransformComponent.h>
  17. namespace ROS2
  18. {
  19. namespace Internal
  20. {
  21. AZ::TransformInterface* GetEntityTransformInterface(const AZ::Entity* entity)
  22. {
  23. // TODO - instead, use EditorFrameComponent to handle Editor-context queries and here only use the "Game" version
  24. if (!entity)
  25. {
  26. AZ_Error("GetEntityTransformInterface", false, "Invalid entity!");
  27. return nullptr;
  28. }
  29. auto* interface = entity->FindComponent<AzFramework::TransformComponent>();
  30. if (interface)
  31. {
  32. return interface;
  33. }
  34. return entity->FindComponent<AzToolsFramework::Components::TransformComponent>();
  35. }
  36. const ROS2FrameComponent* GetFirstROS2FrameAncestor(const AZ::Entity* entity)
  37. {
  38. AZ::TransformInterface* entityTransformInterface = GetEntityTransformInterface(entity);
  39. if (!entityTransformInterface)
  40. {
  41. AZ_Error("GetFirstROS2FrameAncestor", false, "Invalid transform interface!");
  42. return nullptr;
  43. }
  44. AZ::EntityId parentEntityId = entityTransformInterface->GetParentId();
  45. if (!parentEntityId.IsValid())
  46. { // We have reached the top level, there is no parent entity so there can be no parent ROS2Frame
  47. return nullptr;
  48. }
  49. const AZ::Entity* parentEntity = AzToolsFramework::GetEntityById(parentEntityId);
  50. auto* component = Utils::GetGameOrEditorComponent<ROS2FrameComponent>(parentEntity);
  51. if (component == nullptr)
  52. { // Parent entity has no ROS2Frame, but there can still be a ROS2Frame in its ancestors
  53. return GetFirstROS2FrameAncestor(parentEntity);
  54. }
  55. // Found the component!
  56. return component;
  57. }
  58. } // namespace Internal
  59. void ROS2FrameComponent::Activate()
  60. {
  61. m_namespaceConfiguration.PopulateNamespace(IsTopLevel(), GetEntity()->GetName());
  62. if (m_publishTransform)
  63. {
  64. AZ_TracePrintf(
  65. "ROS2FrameComponent",
  66. "Setting up %s transfrom between parent %s and child %s to be published %s",
  67. IsDynamic() ? "dynamic" : "static",
  68. GetParentFrameID().data(),
  69. GetFrameID().data(),
  70. IsDynamic() ? "continuously to /tf" : "once to /tf_static");
  71. m_ros2Transform = AZStd::make_unique<ROS2Transform>(GetParentFrameID(), GetFrameID(), IsDynamic());
  72. if (IsDynamic())
  73. {
  74. AZ::TickBus::Handler::BusConnect();
  75. }
  76. else
  77. {
  78. m_ros2Transform->Publish(GetFrameTransform());
  79. }
  80. }
  81. }
  82. void ROS2FrameComponent::Deactivate()
  83. {
  84. if (m_publishTransform)
  85. {
  86. if (IsDynamic())
  87. {
  88. AZ::TickBus::Handler::BusDisconnect();
  89. }
  90. m_ros2Transform.reset();
  91. }
  92. }
  93. void ROS2FrameComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  94. {
  95. m_ros2Transform->Publish(GetFrameTransform());
  96. }
  97. AZStd::string ROS2FrameComponent::GetGlobalFrameName() const
  98. {
  99. // TODO - parametrize this (typically: "odom", "world" and sometimes "map")
  100. return ROS2Names::GetNamespacedName(GetNamespace(), AZStd::string("odom"));
  101. }
  102. bool ROS2FrameComponent::IsTopLevel() const
  103. {
  104. return GetGlobalFrameName() == GetParentFrameID();
  105. }
  106. bool ROS2FrameComponent::IsDynamic() const
  107. { // TODO - determine by joint type
  108. return IsTopLevel();
  109. }
  110. const ROS2FrameComponent* ROS2FrameComponent::GetParentROS2FrameComponent() const
  111. {
  112. return Internal::GetFirstROS2FrameAncestor(GetEntity());
  113. }
  114. const AZ::Transform& ROS2FrameComponent::GetFrameTransform() const
  115. {
  116. auto transformInterface = Internal::GetEntityTransformInterface(GetEntity());
  117. if (GetParentROS2FrameComponent() != nullptr)
  118. {
  119. return transformInterface->GetLocalTM();
  120. }
  121. return transformInterface->GetWorldTM();
  122. }
  123. AZStd::string ROS2FrameComponent::GetParentFrameID() const
  124. {
  125. if (auto parentFrame = GetParentROS2FrameComponent(); parentFrame != nullptr)
  126. {
  127. return parentFrame->GetFrameID();
  128. }
  129. return GetGlobalFrameName();
  130. }
  131. AZStd::string ROS2FrameComponent::GetFrameID() const
  132. {
  133. return ROS2Names::GetNamespacedName(GetNamespace(), m_frameName);
  134. }
  135. void ROS2FrameComponent::SetFrameID(const AZStd::string& frameId)
  136. {
  137. m_frameName = frameId;
  138. }
  139. AZStd::string ROS2FrameComponent::GetNamespace() const
  140. {
  141. auto parentFrame = GetParentROS2FrameComponent();
  142. AZStd::string parentNamespace("");
  143. if (parentFrame != nullptr)
  144. {
  145. parentNamespace = parentFrame->GetNamespace();
  146. }
  147. return m_namespaceConfiguration.GetNamespace(parentNamespace);
  148. }
  149. void ROS2FrameComponent::Reflect(AZ::ReflectContext* context)
  150. {
  151. NamespaceConfiguration::Reflect(context);
  152. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  153. {
  154. serialize->Class<ROS2FrameComponent, AZ::Component>()
  155. ->Version(1)
  156. ->Field("Namespace Configuration", &ROS2FrameComponent::m_namespaceConfiguration)
  157. ->Field("Frame Name", &ROS2FrameComponent::m_frameName)
  158. ->Field("Publish Transform", &ROS2FrameComponent::m_publishTransform);
  159. if (AZ::EditContext* ec = serialize->GetEditContext())
  160. {
  161. ec->Class<ROS2FrameComponent>("ROS2 Frame", "[ROS2 Frame component]")
  162. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  163. ->Attribute(AZ::Edit::Attributes::Category, "ROS2")
  164. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game"))
  165. ->DataElement(
  166. AZ::Edit::UIHandlers::Default,
  167. &ROS2FrameComponent::m_namespaceConfiguration,
  168. "Namespace Configuration",
  169. "Namespace Configuration")
  170. ->DataElement(AZ::Edit::UIHandlers::Default, &ROS2FrameComponent::m_frameName, "Frame Name", "Frame Name")
  171. ->DataElement(
  172. AZ::Edit::UIHandlers::Default, &ROS2FrameComponent::m_publishTransform, "Publish Transform", "Publish Transform");
  173. }
  174. }
  175. }
  176. void ROS2FrameComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  177. {
  178. provided.push_back(AZ_CRC_CE("ROS2Frame"));
  179. }
  180. void ROS2FrameComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  181. {
  182. incompatible.push_back(AZ_CRC_CE("ROS2Frame"));
  183. }
  184. void ROS2FrameComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  185. {
  186. required.push_back(AZ_CRC("TransformService"));
  187. }
  188. ROS2FrameComponent::ROS2FrameComponent() = default;
  189. ROS2FrameComponent::ROS2FrameComponent(AZStd::string frameId)
  190. : m_frameName(AZStd::move(frameId))
  191. {
  192. }
  193. } // namespace ROS2