|
@@ -12,19 +12,22 @@
|
|
|
#include <AzCore/Serialization/EditContextConstants.inl>
|
|
|
#include <AzCore/Serialization/SerializeContext.h>
|
|
|
#include <AzFramework/Physics/RigidBodyBus.h>
|
|
|
+#include <HingeJointComponent.h>
|
|
|
+#include <PhysX/Joint/PhysXJointRequestsBus.h>
|
|
|
#include <VehicleDynamics/Utilities.h>
|
|
|
|
|
|
namespace ROS2::VehicleDynamics
|
|
|
{
|
|
|
void AckermannDriveModel::Reflect(AZ::ReflectContext* context)
|
|
|
{
|
|
|
+ AckermannModelLimits::Reflect(context);
|
|
|
PidConfiguration::Reflect(context);
|
|
|
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
|
|
|
{
|
|
|
serialize->Class<AckermannDriveModel, DriveModel>()
|
|
|
->Version(1)
|
|
|
->Field("SteeringPID", &AckermannDriveModel::m_steeringPid)
|
|
|
- ->Field("SpeedPID", &AckermannDriveModel::m_speedPid);
|
|
|
+ ->Field("Limits", &AckermannDriveModel::m_limits);
|
|
|
|
|
|
if (AZ::EditContext* ec = serialize->GetEditContext())
|
|
|
{
|
|
@@ -35,11 +38,7 @@ namespace ROS2::VehicleDynamics
|
|
|
&AckermannDriveModel::m_steeringPid,
|
|
|
"Steering PID",
|
|
|
"Configuration of steering PID controller")
|
|
|
- ->DataElement(
|
|
|
- AZ::Edit::UIHandlers::Default,
|
|
|
- &AckermannDriveModel::m_speedPid,
|
|
|
- "Speed PID",
|
|
|
- "Configuration of speed PID controller");
|
|
|
+ ->DataElement(AZ::Edit::UIHandlers::Default, &AckermannDriveModel::m_limits, "Vehicle Limits", "Limits");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -49,11 +48,10 @@ namespace ROS2::VehicleDynamics
|
|
|
m_driveWheelsData.clear();
|
|
|
m_steeringData.clear();
|
|
|
m_vehicleConfiguration = vehicleConfig;
|
|
|
- m_speedPid.InitializePid();
|
|
|
m_steeringPid.InitializePid();
|
|
|
}
|
|
|
|
|
|
- void AckermannDriveModel::ApplyInputState(const VehicleInputsState& inputs, uint64_t deltaTimeNs)
|
|
|
+ void AckermannDriveModel::ApplyState(const VehicleInputs& inputs, AZ::u64 deltaTimeNs)
|
|
|
{
|
|
|
if (m_driveWheelsData.empty())
|
|
|
{
|
|
@@ -64,33 +62,30 @@ namespace ROS2::VehicleDynamics
|
|
|
{
|
|
|
m_steeringData = VehicleDynamics::Utilities::GetAllSteeringEntitiesData(m_vehicleConfiguration);
|
|
|
}
|
|
|
-
|
|
|
- ApplySteering(inputs.m_steering.GetValue(), deltaTimeNs);
|
|
|
- ApplySpeed(inputs.m_speed.GetValue(), deltaTimeNs);
|
|
|
+ const auto jointPositions = inputs.m_jointRequestedPosition;
|
|
|
+ const float steering = jointPositions.empty() ? 0 : jointPositions.front();
|
|
|
+ ApplySteering(steering, deltaTimeNs);
|
|
|
+ ApplySpeed(inputs.m_speed.GetX(), deltaTimeNs);
|
|
|
}
|
|
|
|
|
|
void AckermannDriveModel::ApplyWheelSteering(SteeringDynamicsData& wheelData, float steering, double deltaTimeNs)
|
|
|
{
|
|
|
- const double deltaTimeSec = double(deltaTimeNs) / 1e9;
|
|
|
-
|
|
|
const auto& steeringEntity = wheelData.m_steeringEntity;
|
|
|
- AZ::Vector3 currentSteeringElementRotation;
|
|
|
- AZ::TransformBus::EventResult(currentSteeringElementRotation, steeringEntity, &AZ::TransformBus::Events::GetLocalRotation);
|
|
|
- const float currentSteeringAngle = currentSteeringElementRotation.Dot(wheelData.m_turnAxis);
|
|
|
- const double pidCommand = m_steeringPid.ComputeCommand(steering - currentSteeringAngle, deltaTimeNs);
|
|
|
- if (AZ::IsClose(pidCommand, 0.0))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ const auto& hingeComponent = wheelData.m_hingeJoint;
|
|
|
|
|
|
- const float torque = pidCommand * deltaTimeSec;
|
|
|
- AZ::Transform steeringElementTransform;
|
|
|
- AZ::TransformBus::EventResult(steeringElementTransform, steeringEntity, &AZ::TransformBus::Events::GetWorldTM);
|
|
|
- const auto transformedTorqueVector = steeringElementTransform.TransformVector(wheelData.m_turnAxis * torque);
|
|
|
- Physics::RigidBodyRequestBus::Event(steeringEntity, &Physics::RigidBodyRequests::ApplyAngularImpulse, transformedTorqueVector);
|
|
|
+ auto id = AZ::EntityComponentIdPair(steeringEntity, hingeComponent);
|
|
|
+
|
|
|
+ PhysX::JointRequestBus::Event(
|
|
|
+ id,
|
|
|
+ [&](PhysX::JointRequests* joint)
|
|
|
+ {
|
|
|
+ double currentSteeringAngle = joint->GetPosition();
|
|
|
+ const double pidCommand = m_steeringPid.ComputeCommand(steering - currentSteeringAngle, deltaTimeNs);
|
|
|
+ joint->SetVelocity(pidCommand);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- void AckermannDriveModel::ApplySteering(float steering, uint64_t deltaTimeNs)
|
|
|
+ void AckermannDriveModel::ApplySteering(float steering, AZ::u64 deltaTimeNs)
|
|
|
{
|
|
|
if (m_disabled)
|
|
|
{
|
|
@@ -113,7 +108,7 @@ namespace ROS2::VehicleDynamics
|
|
|
ApplyWheelSteering(m_steeringData.back(), outerSteering, deltaTimeNs);
|
|
|
}
|
|
|
|
|
|
- void AckermannDriveModel::ApplySpeed(float speed, uint64_t deltaTimeNs)
|
|
|
+ void AckermannDriveModel::ApplySpeed(float speed, AZ::u64 deltaTimeNs)
|
|
|
{
|
|
|
if (m_disabled)
|
|
|
{
|
|
@@ -125,43 +120,20 @@ namespace ROS2::VehicleDynamics
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- const double deltaTimeSec = double(deltaTimeNs) / 1e9;
|
|
|
for (const auto& wheelData : m_driveWheelsData)
|
|
|
{
|
|
|
- auto wheelEntity = wheelData.m_wheelEntity;
|
|
|
- AZ::Transform wheelTransform;
|
|
|
- AZ::TransformBus::EventResult(wheelTransform, wheelEntity, &AZ::TransformBus::Events::GetWorldTM);
|
|
|
-
|
|
|
- AZ::Transform inverseWheelTransform = wheelTransform.GetInverse();
|
|
|
- AZ::Vector3 currentAngularVelocity;
|
|
|
- Physics::RigidBodyRequestBus::EventResult(currentAngularVelocity, wheelEntity, &Physics::RigidBodyRequests::GetAngularVelocity);
|
|
|
- currentAngularVelocity = inverseWheelTransform.TransformVector(currentAngularVelocity);
|
|
|
- auto currentAngularSpeedX = currentAngularVelocity.Dot(wheelData.m_driveAxis);
|
|
|
+ const auto wheelEntity = wheelData.m_wheelEntity;
|
|
|
float wheelRadius = wheelData.m_wheelRadius;
|
|
|
- if (AZ::IsClose(wheelRadius, 0.0f))
|
|
|
- {
|
|
|
- const float defaultFloatRadius = 0.35f;
|
|
|
- AZ_Warning("ApplySpeed", false, "Wheel radius is zero (or too close to zero), resetting to default %f", defaultFloatRadius);
|
|
|
- wheelRadius = defaultFloatRadius;
|
|
|
- }
|
|
|
-
|
|
|
- auto desiredAngularSpeedX = speed / wheelRadius;
|
|
|
- double pidCommand = m_speedPid.ComputeCommand(desiredAngularSpeedX - currentAngularSpeedX, deltaTimeNs);
|
|
|
- if (AZ::IsClose(pidCommand, 0.0))
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- auto impulse = pidCommand * deltaTimeSec;
|
|
|
-
|
|
|
- auto transformedTorqueVector = wheelTransform.TransformVector(wheelData.m_driveAxis * impulse);
|
|
|
- Physics::RigidBodyRequestBus::Event(wheelEntity, &Physics::RigidBodyRequests::ApplyAngularImpulse, transformedTorqueVector);
|
|
|
+ const auto hingeComponent = wheelData.m_hingeJoint;
|
|
|
+ const auto id = AZ::EntityComponentIdPair(wheelEntity, hingeComponent);
|
|
|
+ AZ_Assert(wheelRadius != 0, "wheelRadius must be non-zero");
|
|
|
+ auto desiredAngularSpeedX = (speed / wheelRadius);
|
|
|
+ PhysX::JointRequestBus::Event(id, &PhysX::JointRequests::SetVelocity, desiredAngularSpeedX);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- void AckermannDriveModel::SetDisabled(bool isDisabled)
|
|
|
+ const VehicleModelLimits* AckermannDriveModel::GetVehicleLimitPtr() const
|
|
|
{
|
|
|
- m_disabled = isDisabled;
|
|
|
+ return &m_limits;
|
|
|
}
|
|
|
-
|
|
|
} // namespace ROS2::VehicleDynamics
|