2
0

SkidSteeringDriveModel.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  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 "SkidSteeringDriveModel.h"
  9. #include <AzCore/Component/TransformBus.h>
  10. #include <AzCore/Serialization/EditContext.h>
  11. #include <AzCore/Serialization/EditContextConstants.inl>
  12. #include <AzCore/Serialization/SerializeContext.h>
  13. #include <AzFramework/Physics/RigidBodyBus.h>
  14. #include <HingeJointComponent.h>
  15. #include <PhysX/Joint/PhysXJointRequestsBus.h>
  16. #include <VehicleDynamics/Utilities.h>
  17. namespace ROS2Controllers::VehicleDynamics
  18. {
  19. void SkidSteeringDriveModel::Reflect(AZ::ReflectContext* context)
  20. {
  21. SkidSteeringModelLimits::Reflect(context);
  22. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  23. {
  24. serialize->Class<SkidSteeringDriveModel, DriveModel>()->Version(1)->Field("Limits", &SkidSteeringDriveModel::m_limits);
  25. if (AZ::EditContext* ec = serialize->GetEditContext())
  26. {
  27. ec->Class<SkidSteeringDriveModel>("Skid Steering Drive Model", "Configuration of a simplified vehicle dynamics drive model")
  28. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  29. ->DataElement(AZ::Edit::UIHandlers::Default, &SkidSteeringDriveModel::m_limits, "Vehicle Limits", "Limits");
  30. }
  31. }
  32. }
  33. SkidSteeringDriveModel::SkidSteeringDriveModel(const SkidSteeringModelLimits& limits)
  34. : m_limits(limits)
  35. {
  36. }
  37. void SkidSteeringDriveModel::Activate(const VehicleConfiguration& vehicleConfig)
  38. {
  39. m_config = vehicleConfig;
  40. m_wheelsData.clear();
  41. m_initialized = false;
  42. }
  43. void SkidSteeringDriveModel::ComputeWheelsData()
  44. {
  45. // Compute number of drive axles to scale the contribution of each wheel to vehicle's velocity
  46. int driveAxlesCount = 0;
  47. for (const auto& axle : m_config.m_axles)
  48. {
  49. if (axle.m_isDrive && axle.m_axleWheels.size() > 1)
  50. {
  51. driveAxlesCount++;
  52. }
  53. AZ_Warning(
  54. "SkidSteeringDriveModel",
  55. axle.m_axleWheels.size() > 1,
  56. "Axle %s has not enough wheels (%d)",
  57. axle.m_axleTag.c_str(),
  58. axle.m_axleWheels.size());
  59. }
  60. AZ_Warning("SkidSteeringDriveModel", driveAxlesCount != 0, "Skid steering model does not have any drive wheels.");
  61. // Find the contribution of each wheel to vehicle's velocity
  62. for (const auto& axle : m_config.m_axles)
  63. {
  64. const auto wheelCount = axle.m_axleWheels.size();
  65. if (!axle.m_isDrive || wheelCount <= 1)
  66. {
  67. continue;
  68. }
  69. for (size_t wheelId = 0; wheelId < wheelCount; wheelId++)
  70. {
  71. const auto data = ComputeSingleWheelData(wheelId, axle, driveAxlesCount);
  72. if (data.wheelControllerComponentPtr != nullptr)
  73. {
  74. m_wheelsData.emplace_back(AZStd::move(data));
  75. }
  76. }
  77. }
  78. m_initialized = true;
  79. }
  80. SkidSteeringDriveModel::SkidSteeringWheelData SkidSteeringDriveModel::ComputeSingleWheelData(
  81. const int wheelId, const AxleConfiguration& axle, const int axlesCount) const
  82. {
  83. SkidSteeringDriveModel::SkidSteeringWheelData out;
  84. AZ_Assert(axle.m_wheelRadius != 0, "axle.m_wheelRadius must be non-zero");
  85. const auto wheelEntityId = axle.m_axleWheels[wheelId];
  86. AZ::Entity* wheelEntityPtr = nullptr;
  87. AZ::ComponentApplicationBus::BroadcastResult(wheelEntityPtr, &AZ::ComponentApplicationRequests::FindEntity, wheelEntityId);
  88. AZ_Assert(wheelEntityPtr, "The wheelEntity should not be null here");
  89. out.wheelData = VehicleDynamics::Utilities::GetWheelData(wheelEntityId, axle.m_wheelRadius);
  90. out.wheelControllerComponentPtr = wheelEntityPtr->FindComponent<WheelControllerComponent>();
  91. if (out.wheelControllerComponentPtr)
  92. {
  93. const auto wheelsCount = axle.m_axleWheels.size();
  94. const float normalizedWheelId = -1.f + 2.f * wheelId / (wheelsCount - 1);
  95. out.wheelPosition = normalizedWheelId * (m_config.m_track / 2.f);
  96. out.dX = axle.m_wheelRadius / (wheelsCount * axlesCount);
  97. out.dPhi = axle.m_wheelRadius / (out.wheelPosition * axlesCount * axle.m_axleWheels.size());
  98. AZ::Transform hingeTransform = Utilities::GetJointTransform(out.wheelData);
  99. out.axis = hingeTransform.TransformVector({ 0.f, 1.f, 0.f });
  100. }
  101. return out;
  102. }
  103. AZStd::pair<AZ::Vector3, AZ::Vector3> SkidSteeringDriveModel::GetVelocityFromModel()
  104. {
  105. if (!m_initialized)
  106. {
  107. ComputeWheelsData();
  108. }
  109. float dX = 0; // accumulated contribution to vehicle's linear movements of every wheel
  110. float dPhi = 0; // accumulated contribution to vehicle's rotational movements of every wheel
  111. for (const auto& wheel : m_wheelsData)
  112. {
  113. const float omega = wheel.axis.Dot(wheel.wheelControllerComponentPtr->GetRotationVelocity());
  114. dX += omega * wheel.dX;
  115. dPhi += omega * wheel.dPhi;
  116. }
  117. return AZStd::pair<AZ::Vector3, AZ::Vector3>{ { dX, 0, 0 }, { 0, 0, dPhi } };
  118. }
  119. void SkidSteeringDriveModel::ApplyState(const VehicleInputs& inputs, AZ::u64 deltaTimeNs)
  120. {
  121. if (m_disabled)
  122. {
  123. return;
  124. }
  125. if (!m_initialized)
  126. {
  127. ComputeWheelsData();
  128. }
  129. const float angularTargetSpeed = inputs.m_angularRates.GetZ();
  130. const float linearTargetSpeed = inputs.m_speed.GetX();
  131. const float angularAcceleration = m_limits.GetAngularAcceleration();
  132. const float linearAcceleration = m_limits.GetLinearAcceleration();
  133. const float maxLinearVelocity = m_limits.GetLinearSpeedLimit();
  134. const float maxAngularVelocity = m_limits.GetAngularSpeedLimit();
  135. m_currentAngularVelocity = Utilities::ComputeRampVelocity(
  136. angularTargetSpeed, m_currentAngularVelocity, deltaTimeNs, angularAcceleration, maxAngularVelocity);
  137. m_currentLinearVelocity =
  138. Utilities::ComputeRampVelocity(linearTargetSpeed, m_currentLinearVelocity, deltaTimeNs, linearAcceleration, maxLinearVelocity);
  139. for (const auto& wheel : m_wheelsData)
  140. {
  141. const float wheelRate =
  142. (m_currentLinearVelocity + m_currentAngularVelocity * wheel.wheelPosition) / wheel.wheelData.m_wheelRadius;
  143. VehicleDynamics::Utilities::SetWheelRotationSpeed(wheel.wheelData, wheelRate);
  144. }
  145. }
  146. const VehicleModelLimits* SkidSteeringDriveModel::GetVehicleLimitPtr() const
  147. {
  148. return &m_limits;
  149. }
  150. } // namespace ROS2Controllers::VehicleDynamics