ROS2ImuSensorComponent.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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 "ROS2ImuSensorComponent.h"
  9. #include <ROS2/ROS2Bus.h>
  10. #include <ROS2/Utilities/ROS2Conversions.h>
  11. #include <ROS2/Utilities/ROS2Names.h>
  12. #include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
  13. #include <Source/RigidBodyComponent.h>
  14. #include <AzCore/Component/Entity.h>
  15. #include <AzCore/Script/ScriptTimePoint.h>
  16. #include <AzCore/Serialization/EditContext.h>
  17. #include <AzCore/Serialization/EditContextConstants.inl>
  18. #include <AzCore/std/numeric.h>
  19. #include <AzCore/std/smart_ptr/make_shared.h>
  20. namespace ROS2Sensors
  21. {
  22. namespace Internal
  23. {
  24. const char* kImuMsgType = "sensor_msgs::msg::Imu";
  25. }
  26. void ROS2ImuSensorComponent::Reflect(AZ::ReflectContext* context)
  27. {
  28. ImuSensorConfiguration::Reflect(context);
  29. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  30. {
  31. serializeContext->Class<ROS2ImuSensorComponent, SensorBaseType>()->Version(3)->Field(
  32. "imuSensorConfiguration", &ROS2ImuSensorComponent::m_imuConfiguration);
  33. if (auto* editContext = serializeContext->GetEditContext())
  34. {
  35. editContext->Class<ROS2ImuSensorComponent>("ROS2 Imu Sensor", "Imu sensor component")
  36. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  37. ->Attribute(AZ::Edit::Attributes::Category, "ROS2")
  38. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
  39. ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/ROS2ImuSensor.svg")
  40. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/ROS2ImuSensor.svg")
  41. ->DataElement(
  42. AZ::Edit::UIHandlers::Default,
  43. &ROS2ImuSensorComponent::m_imuConfiguration,
  44. "Imu sensor configuration",
  45. "Imu sensor configuration")
  46. ->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly);
  47. }
  48. }
  49. }
  50. ROS2ImuSensorComponent::ROS2ImuSensorComponent()
  51. {
  52. const AZStd::string type = Internal::kImuMsgType;
  53. ROS2::TopicConfiguration pc;
  54. pc.m_type = type;
  55. pc.m_topic = "imu";
  56. m_sensorConfiguration.m_frequency = 50;
  57. m_sensorConfiguration.m_publishersConfigurations.insert(AZStd::make_pair(type, pc));
  58. }
  59. ROS2ImuSensorComponent::ROS2ImuSensorComponent(
  60. const ROS2::SensorConfiguration& sensorConfiguration, const ImuSensorConfiguration& imuConfiguration)
  61. : m_imuConfiguration(imuConfiguration)
  62. {
  63. m_sensorConfiguration = sensorConfiguration;
  64. }
  65. void ROS2ImuSensorComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  66. {
  67. required.push_back(AZ_CRC_CE("PhysicsDynamicRigidBodyService"));
  68. required.push_back(AZ_CRC_CE("ROS2Frame"));
  69. }
  70. void ROS2ImuSensorComponent::Activate()
  71. {
  72. ROS2SensorComponentBase::Activate();
  73. auto ros2Node = ROS2::ROS2Interface::Get()->GetNode();
  74. AZ_Assert(m_sensorConfiguration.m_publishersConfigurations.size() == 1, "Invalid configuration of publishers for IMU sensor");
  75. m_imuMsg.header.frame_id = GetFrameID().c_str();
  76. const auto publisherConfig = m_sensorConfiguration.m_publishersConfigurations[Internal::kImuMsgType];
  77. const auto fullTopic = ROS2::ROS2Names::GetNamespacedName(GetNamespace(), publisherConfig.m_topic);
  78. m_imuPublisher = ros2Node->create_publisher<sensor_msgs::msg::Imu>(fullTopic.data(), publisherConfig.GetQoS());
  79. ConfigureSensor();
  80. StartSensor(
  81. m_sensorConfiguration.m_frequency,
  82. [this](float imuDeltaTime, AzPhysics::SceneHandle sceneHandle, float physicsDeltaTime)
  83. {
  84. if (!m_sensorConfiguration.m_publishingEnabled)
  85. {
  86. return;
  87. }
  88. OnImuEvent(imuDeltaTime, sceneHandle, physicsDeltaTime);
  89. },
  90. [this]([[maybe_unused]] AzPhysics::SceneHandle sceneHandle, float physicsDeltaTime)
  91. {
  92. OnPhysicsEvent(sceneHandle);
  93. });
  94. ImuConfigurationRequestBus::Handler::BusConnect(GetEntityId());
  95. }
  96. void ROS2ImuSensorComponent::Deactivate()
  97. {
  98. ImuConfigurationRequestBus::Handler::BusDisconnect(GetEntityId());
  99. StopSensor();
  100. m_bodyHandle = AzPhysics::InvalidSimulatedBodyHandle;
  101. m_imuPublisher.reset();
  102. ROS2SensorComponentBase::Deactivate();
  103. }
  104. void ROS2ImuSensorComponent::OnPhysicsEvent(AzPhysics::SceneHandle sceneHandle)
  105. {
  106. if (m_bodyHandle == AzPhysics::InvalidSimulatedBodyHandle)
  107. {
  108. AzPhysics::RigidBody* rigidBody = nullptr;
  109. AZ::EntityId entityId = GetEntityId();
  110. Physics::RigidBodyRequestBus::EventResult(rigidBody, entityId, &Physics::RigidBodyRequests::GetRigidBody);
  111. if (!rigidBody)
  112. {
  113. AZ_Error(
  114. "ROS2ImuSensorComponent",
  115. false,
  116. "Entity %s does not have a rigid body - stopping Imu sensor.",
  117. entityId.ToString().c_str());
  118. StopSensor();
  119. return;
  120. }
  121. m_bodyHandle = rigidBody->m_bodyHandle;
  122. }
  123. auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  124. auto* body = sceneInterface->GetSimulatedBodyFromHandle(sceneHandle, m_bodyHandle);
  125. AZ_Assert(body, "Requested simulated body does not exist");
  126. auto* rigidbody = azrtti_cast<AzPhysics::RigidBody*>(body);
  127. AZ_Assert(rigidbody, "Requested simulated body is not a rigid body");
  128. auto inv = rigidbody->GetTransform().GetInverse();
  129. const auto linearVelocity = inv.TransformVector(rigidbody->GetLinearVelocity());
  130. m_filterAcceleration.push_back(linearVelocity);
  131. const auto angularVelocity = inv.TransformVector(rigidbody->GetAngularVelocity());
  132. m_filterAngularVelocity.push_back(angularVelocity);
  133. if (m_filterAcceleration.size() > m_imuConfiguration.m_filterSize)
  134. {
  135. m_filterAcceleration.pop_front();
  136. m_filterAngularVelocity.pop_front();
  137. }
  138. }
  139. void ROS2ImuSensorComponent::OnImuEvent([[maybe_unused]] float imuDeltaTime, AzPhysics::SceneHandle sceneHandle, float physicsDeltaTime)
  140. {
  141. const AZ::Vector3 linearVelocityFilter =
  142. AZStd::accumulate(m_filterAcceleration.begin(), m_filterAcceleration.end(), AZ::Vector3{ 0 }) / m_filterAcceleration.size();
  143. const AZ::Vector3 angularRateFiltered =
  144. AZStd::accumulate(m_filterAngularVelocity.begin(), m_filterAngularVelocity.end(), AZ::Vector3{ 0 }) /
  145. m_filterAngularVelocity.size();
  146. // Physics delta time is used here intentionally - linear velocities are accumulated with that delta (see OnPhysicsEvent method).
  147. auto acc = (linearVelocityFilter - m_previousLinearVelocity) / imuDeltaTime;
  148. auto* sceneInterface = AZ::Interface<AzPhysics::SceneInterface>::Get();
  149. auto* body = sceneInterface->GetSimulatedBodyFromHandle(sceneHandle, m_bodyHandle);
  150. auto rigidbody = azrtti_cast<AzPhysics::RigidBody*>(body);
  151. auto inv = rigidbody->GetTransform().GetInverse();
  152. m_previousLinearVelocity = linearVelocityFilter;
  153. m_acceleration = acc - angularRateFiltered.Cross(linearVelocityFilter);
  154. if (m_imuConfiguration.m_includeGravity)
  155. {
  156. const auto gravity = sceneInterface->GetGravity(sceneHandle);
  157. m_acceleration -= inv.TransformVector(gravity);
  158. }
  159. m_imuMsg.linear_acceleration = ROS2::ROS2Conversions::ToROS2Vector3(m_acceleration);
  160. m_imuMsg.linear_acceleration_covariance = ROS2::ROS2Conversions::ToROS2Covariance(m_linearAccelerationCovariance);
  161. m_imuMsg.angular_velocity = ROS2::ROS2Conversions::ToROS2Vector3(angularRateFiltered);
  162. m_imuMsg.angular_velocity_covariance = ROS2::ROS2Conversions::ToROS2Covariance(m_angularVelocityCovariance);
  163. if (m_imuConfiguration.m_absoluteRotation)
  164. {
  165. m_imuMsg.orientation = ROS2::ROS2Conversions::ToROS2Quaternion(rigidbody->GetTransform().GetRotation());
  166. m_imuMsg.orientation_covariance = ROS2::ROS2Conversions::ToROS2Covariance(m_orientationCovariance);
  167. }
  168. m_imuMsg.header.stamp = ROS2::ROS2Interface::Get()->GetROSTimestamp();
  169. this->m_imuPublisher->publish(m_imuMsg);
  170. }
  171. AZ::Matrix3x3 ROS2ImuSensorComponent::ToDiagonalCovarianceMatrix(const AZ::Vector3& variance)
  172. {
  173. AZ::Matrix3x3 covarianceMatrix;
  174. covarianceMatrix.SetElement(0, 0, variance.GetX());
  175. covarianceMatrix.SetElement(1, 1, variance.GetY());
  176. covarianceMatrix.SetElement(2, 2, variance.GetZ());
  177. return covarianceMatrix;
  178. }
  179. void ROS2ImuSensorComponent::ConfigureSensor()
  180. {
  181. m_linearAccelerationCovariance = ToDiagonalCovarianceMatrix(m_imuConfiguration.m_linearAccelerationVariance);
  182. m_angularVelocityCovariance = ToDiagonalCovarianceMatrix(m_imuConfiguration.m_angularVelocityVariance);
  183. m_orientationCovariance = ToDiagonalCovarianceMatrix(m_imuConfiguration.m_orientationVariance);
  184. }
  185. const ImuSensorConfiguration ROS2ImuSensorComponent::GetConfiguration()
  186. {
  187. return m_imuConfiguration;
  188. }
  189. void ROS2ImuSensorComponent::SetConfiguration(const ImuSensorConfiguration& configuration)
  190. {
  191. m_imuConfiguration = configuration;
  192. ConfigureSensor();
  193. }
  194. int ROS2ImuSensorComponent::GetFilterSize()
  195. {
  196. return m_imuConfiguration.m_filterSize;
  197. }
  198. void ROS2ImuSensorComponent::SetFilterSize(int filterSize)
  199. {
  200. if (filterSize < m_imuConfiguration.m_minFilterSize || filterSize > m_imuConfiguration.m_maxFilterSize)
  201. {
  202. AZ_Error(
  203. "ROS2ImuSensorComponent",
  204. false,
  205. "Filter size %d is out of bounds [%d, %d].",
  206. filterSize,
  207. m_imuConfiguration.m_minFilterSize,
  208. m_imuConfiguration.m_maxFilterSize);
  209. return;
  210. }
  211. m_imuConfiguration.m_filterSize = filterSize;
  212. }
  213. bool ROS2ImuSensorComponent::GetIncludeGravity()
  214. {
  215. return m_imuConfiguration.m_includeGravity;
  216. }
  217. void ROS2ImuSensorComponent::SetIncludeGravity(bool includeGravity)
  218. {
  219. m_imuConfiguration.m_includeGravity = includeGravity;
  220. }
  221. bool ROS2ImuSensorComponent::GetAbsoluteRotation()
  222. {
  223. return m_imuConfiguration.m_absoluteRotation;
  224. }
  225. void ROS2ImuSensorComponent::SetAbsoluteRotation(bool absoluteRotation)
  226. {
  227. m_imuConfiguration.m_absoluteRotation = absoluteRotation;
  228. }
  229. AZ::Vector3 ROS2ImuSensorComponent::GetOrientationVariance()
  230. {
  231. return m_imuConfiguration.m_orientationVariance;
  232. }
  233. void ROS2ImuSensorComponent::SetOrientationVariance(const AZ::Vector3& orientationVariance)
  234. {
  235. m_imuConfiguration.m_orientationVariance = orientationVariance;
  236. ConfigureSensor();
  237. }
  238. AZ::Vector3 ROS2ImuSensorComponent::GetAngularVelocityVariance()
  239. {
  240. return m_imuConfiguration.m_angularVelocityVariance;
  241. }
  242. void ROS2ImuSensorComponent::SetAngularVelocityVariance(const AZ::Vector3& angularVelocityVariance)
  243. {
  244. m_imuConfiguration.m_angularVelocityVariance = angularVelocityVariance;
  245. ConfigureSensor();
  246. }
  247. AZ::Vector3 ROS2ImuSensorComponent::GetLinearAccelerationVariance()
  248. {
  249. return m_imuConfiguration.m_linearAccelerationVariance;
  250. }
  251. void ROS2ImuSensorComponent::SetLinearAccelerationVariance(const AZ::Vector3& linearAccelerationVariance)
  252. {
  253. m_imuConfiguration.m_linearAccelerationVariance = linearAccelerationVariance;
  254. ConfigureSensor();
  255. }
  256. } // namespace ROS2Sensors