ROS2SystemComponent.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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 <signal.h>
  9. #include "ROS2SystemComponent.h"
  10. #include <Lidar/LidarCore.h>
  11. #include <ROS2/Clock/RealTimeSource.h>
  12. #include <ROS2/Clock/ROS2TimeSource.h>
  13. #include <ROS2/Clock/SimulationTimeSource.h>
  14. #include <ROS2/Communication/PublisherConfiguration.h>
  15. #include <ROS2/Communication/QoS.h>
  16. #include <ROS2/Communication/TopicConfiguration.h>
  17. #include <ROS2/Sensor/SensorConfiguration.h>
  18. #include <ROS2/Utilities/Controllers/PidConfiguration.h>
  19. #include <VehicleDynamics/VehicleModelComponent.h>
  20. #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
  21. #include <AzCore/Serialization/EditContext.h>
  22. #include <AzCore/Serialization/EditContextConstants.inl>
  23. #include <AzCore/Serialization/SerializeContext.h>
  24. #include <AzCore/Settings/SettingsRegistry.h>
  25. #include <AzCore/Time/ITime.h>
  26. #include <AzCore/std/smart_ptr/make_shared.h>
  27. #include <AzCore/std/string/string_view.h>
  28. #include <AzFramework/API/ApplicationAPI.h>
  29. namespace ROS2
  30. {
  31. constexpr AZStd::string_view ClockTypeConfigurationKey = "/O3DE/ROS2/ClockType";
  32. constexpr AZStd::string_view PublishClockConfigurationKey = "/O3DE/ROS2/PublishClock";
  33. void ROS2SystemComponent::Reflect(AZ::ReflectContext* context)
  34. {
  35. // Reflect structs not strictly owned by any single component
  36. QoS::Reflect(context);
  37. TopicConfiguration::Reflect(context);
  38. PublisherConfiguration::Reflect(context);
  39. LidarCore::Reflect(context);
  40. SensorConfiguration::Reflect(context);
  41. VehicleDynamics::VehicleModelComponent::Reflect(context);
  42. ROS2::Controllers::PidConfiguration::Reflect(context);
  43. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  44. {
  45. serialize->Class<ROS2SystemComponent, AZ::Component>()->Version(0);
  46. if (AZ::EditContext* ec = serialize->GetEditContext())
  47. {
  48. ec->Class<ROS2SystemComponent>(
  49. "ROS 2 System Component",
  50. "This component is responsible for creating ROS 2 node and executor, provides ROS 2 interfaces, manages ROS 2 clock and "
  51. "publishes transforms.")
  52. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  53. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("System"))
  54. ->Attribute(AZ::Edit::Attributes::Category, "ROS2")
  55. ->Attribute(AZ::Edit::Attributes::AutoExpand, true);
  56. }
  57. }
  58. }
  59. void ROS2SystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  60. {
  61. provided.push_back(AZ_CRC_CE("ROS2Service"));
  62. }
  63. void ROS2SystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  64. {
  65. incompatible.push_back(AZ_CRC_CE("ROS2Service"));
  66. }
  67. void ROS2SystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
  68. {
  69. required.push_back(AZ_CRC("AssetDatabaseService", 0x3abf5601));
  70. required.push_back(AZ_CRC("RPISystem", 0xf2add773));
  71. }
  72. void ROS2SystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
  73. {
  74. }
  75. ROS2SystemComponent::ROS2SystemComponent()
  76. {
  77. if (ROS2Interface::Get() == nullptr)
  78. {
  79. ROS2Interface::Register(this);
  80. }
  81. }
  82. ROS2SystemComponent::~ROS2SystemComponent()
  83. {
  84. if (ROS2Interface::Get() == this)
  85. {
  86. ROS2Interface::Unregister(this);
  87. }
  88. rclcpp::shutdown();
  89. }
  90. void ROS2SystemComponent::Init()
  91. {
  92. rclcpp::init(0, 0);
  93. // handle signals, e.g. via `Ctrl+C` hotkey or `kill` command
  94. auto handler = [](int sig){
  95. rclcpp::shutdown(); // shutdown rclcpp
  96. std::raise(sig); // shutdown o3de
  97. };
  98. signal(SIGINT, handler);
  99. signal(SIGTERM, handler);
  100. }
  101. void ROS2SystemComponent::InitClock()
  102. {
  103. AZStd::unordered_map<AZStd::string, AZStd::function<AZStd::unique_ptr<ITimeSource>()>> clocksMap;
  104. clocksMap["realtime"] = []()
  105. {
  106. AZ_Info("ROS2SystemComponent", "Enabling realtime clock.");
  107. return AZStd::make_unique<RealTimeSource>();
  108. };
  109. clocksMap["simulation"] = []()
  110. {
  111. AZ_Info("ROS2SystemComponent", "Enabling simulation clock.");
  112. return AZStd::make_unique<SimulationTimeSource>();
  113. };
  114. clocksMap["ros2"] = []()
  115. {
  116. AZ_Info("ROS2SystemComponent", "Enabling ros 2 clock.");
  117. return AZStd::make_unique<ROS2TimeSource>();
  118. };
  119. AZStd::string clockType{ "" };
  120. bool publishClock{ true };
  121. auto* registry = AZ::SettingsRegistry::Get();
  122. AZ_Assert(registry, "No Registry available");
  123. if (registry)
  124. {
  125. registry->Get(publishClock, PublishClockConfigurationKey);
  126. registry->Get(clockType, ClockTypeConfigurationKey);
  127. if (clocksMap.contains(clockType))
  128. {
  129. m_simulationClock = AZStd::make_unique<ROS2Clock>(clocksMap[clockType](), publishClock);
  130. return;
  131. }
  132. }
  133. AZ_Info("ROS2SystemComponent", "Cannot read registry or the clock type '%s' is unknown, enabling simulation clock.", clockType.c_str());
  134. m_simulationClock = AZStd::make_unique<ROS2Clock>(clocksMap["simulation"](), publishClock);
  135. }
  136. void ROS2SystemComponent::Activate()
  137. {
  138. InitClock();
  139. m_simulationClock->Activate();
  140. m_ros2Node = std::make_shared<rclcpp::Node>("o3de_ros2_node");
  141. m_executor = AZStd::make_shared<rclcpp::executors::SingleThreadedExecutor>();
  142. m_executor->add_node(m_ros2Node);
  143. m_staticTFBroadcaster = AZStd::make_unique<tf2_ros::StaticTransformBroadcaster>(m_ros2Node);
  144. m_dynamicTFBroadcaster = AZStd::make_unique<tf2_ros::TransformBroadcaster>(m_ros2Node);
  145. ROS2RequestBus::Handler::BusConnect();
  146. AZ::TickBus::Handler::BusConnect();
  147. m_nodeChangedEvent.Signal(m_ros2Node);
  148. }
  149. void ROS2SystemComponent::Deactivate()
  150. {
  151. AZ::TickBus::Handler::BusDisconnect();
  152. ROS2RequestBus::Handler::BusDisconnect();
  153. if (m_simulationClock) {
  154. m_simulationClock->Deactivate();
  155. }
  156. m_dynamicTFBroadcaster.reset();
  157. m_staticTFBroadcaster.reset();
  158. if (m_executor)
  159. {
  160. if (m_ros2Node) {
  161. m_executor->remove_node(m_ros2Node);
  162. }
  163. m_executor.reset();
  164. }
  165. m_simulationClock.reset();
  166. m_ros2Node.reset();
  167. m_nodeChangedEvent.Signal(m_ros2Node);
  168. }
  169. builtin_interfaces::msg::Time ROS2SystemComponent::GetROSTimestamp() const
  170. {
  171. return m_simulationClock->GetROSTimestamp();
  172. }
  173. std::shared_ptr<rclcpp::Node> ROS2SystemComponent::GetNode() const
  174. {
  175. return m_ros2Node;
  176. }
  177. void ROS2SystemComponent::ConnectOnNodeChanged(NodeChangedEvent::Handler& handler)
  178. {
  179. handler.Connect(m_nodeChangedEvent);
  180. }
  181. const ROS2Clock& ROS2SystemComponent::GetSimulationClock() const
  182. {
  183. return *m_simulationClock;
  184. }
  185. void ROS2SystemComponent::BroadcastTransform(const geometry_msgs::msg::TransformStamped& t, bool isDynamic)
  186. {
  187. if (isDynamic)
  188. {
  189. m_frameTransforms.push_back(t);
  190. }
  191. else
  192. {
  193. m_staticTFBroadcaster->sendTransform(t);
  194. }
  195. }
  196. void ROS2SystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  197. {
  198. if (rclcpp::ok())
  199. {
  200. m_dynamicTFBroadcaster->sendTransform(m_frameTransforms);
  201. m_frameTransforms.clear();
  202. m_simulationClock->Tick();
  203. m_executor->spin_some();
  204. }
  205. }
  206. } // namespace ROS2