Added joints, TestBot, Setup and simulate functions added. TODO: SolvePositions, SolveVelocities

Models need to have Sockets "JointPrev" and "JointNext" for information about joint position and rotation axis.
main
Benjamin Kraft 2 years ago
parent 3106c65f98
commit 61f5e7ae40
  1. 5
      Config/DefaultEngine.ini
  2. BIN
      Content/Blueprints/BP_Puma.uasset
  3. BIN
      Content/Blueprints/BP_Robot.uasset
  4. BIN
      Content/Blueprints/BP_TestBot.uasset
  5. BIN
      Content/Levels/Main.umap
  6. BIN
      Content/Models/puma_link1.uasset
  7. BIN
      Content/Models/puma_link2.uasset
  8. BIN
      Content/Models/puma_link3.uasset
  9. 8
      Source/PBDRobotics/Joint.cpp
  10. 34
      Source/PBDRobotics/Joint.h
  11. 86
      Source/PBDRobotics/Link.cpp
  12. 47
      Source/PBDRobotics/Link.h
  13. 35
      Source/PBDRobotics/Robot.cpp
  14. 8
      Source/PBDRobotics/Robot.h
  15. 27
      Source/PBDRobotics/util.h

@ -19,3 +19,8 @@ AppliedDefaultGraphicsPerformance=Maximum
[/Script/Engine.RendererSettings] [/Script/Engine.RendererSettings]
r.DefaultFeature.AutoExposure=False r.DefaultFeature.AutoExposure=False
[CoreRedirects]
+ClassRedirects=(OldName="/Script/PBDRobotics.Joint",NewName="/Script/PBDRobotics.Joint")
+PropertyRedirects=(OldName="/Script/PBDRobotics.Joint.PrevLink",NewName="/Script/PBDRobotics.Joint.FirstLink")
+PropertyRedirects=(OldName="/Script/PBDRobotics.Joint.NextLink",NewName="/Script/PBDRobotics.Joint.SecondLink")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -0,0 +1,8 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "Joint.h"
UJoint::UJoint()
{
}

@ -0,0 +1,34 @@
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Eigen/Dense"
#include "CoreMinimal.h"
#include "Joint.generated.h"
using namespace Eigen;
class ULink;
/**
*
*/
UCLASS(BlueprintType, ClassGroup=(Custom))
class PBDROBOTICS_API UJoint : public UObject
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite)
ULink* FirstLink;
UPROPERTY(BlueprintReadWrite)
ULink* SecondLink;
Vector3d FirstRotateAxis;
Vector3d SecondRotateAxis;
Vector3d FirstLocalPosition;
Vector3d SecondLocalPosition;
UJoint();
};

@ -5,39 +5,77 @@
#include <iostream> #include <iostream>
#include "util.h"
#include "Eigen/Dense" #include "Eigen/Dense"
#include "Engine/StaticMeshSocket.h"
Eigen::Matrix3d ULink::GetMomentOfInertia() const { using namespace Eigen;
const FVector FI = this->GetInertiaTensor();
// Inertial tensor of rotation // Inertia tensor in world space
const Eigen::Vector3d I(FI.X, FI.Y, FI.Z); Matrix3d ULink::GetMomentOfInertia() const {
return GetRotationMatrix() * Inertia_Tensor_Local;
}
// Moment of inertia Matrix3d ULink::GetRotationMatrix() const{
const Eigen::Matrix3d I0;// = R.transpose() * I * R; const FQuat Q = this->GetRelativeRotation().Quaternion();
return Quaterniond(Q.W, Q.X, Q.Y, Q.Z).toRotationMatrix();
}
return I0; void ULink::Setup(){
SetupJoints();
SetupProperties();
}
void ULink::SetupProperties(){
Inertia_Tensor_Local = ToEigen(GetInertiaTensor()).asDiagonal();
CenterOfMass = ToEigen(GetCenterOfMass());
Position = ToEigen(GetComponentLocation());
Velocity = Vector3d::Zero();
Mass = IsBase ? INFINITY : CalculateMass();
Orientation = Quaterniond::Identity();
AngularVelocity = Vector3d::Zero();
Inertia = GetMomentOfInertia();
} }
Eigen::Matrix3d ULink::GetRotationMatrix() const{ void ULink::SetupJoints() const {
const FQuat fq = this->GetRelativeRotation().Quaternion(); if (const UStaticMeshSocket* Socket = GetSocketByName("JointPrev")){
const Eigen::Vector3d q(fq.X, fq.Y, fq.Z); if (PrevJoint){
const double w = fq.W; PrevJoint->SecondLocalPosition = ToEigen(Socket->RelativeLocation);
Eigen::Matrix3d q_hat; PrevJoint->SecondRotateAxis = ToEigen(Socket->RelativeRotation.Vector());
q_hat << 0, -q.z(), q.y(), }
q.z(), 0, -q.x(), }
-q.y(), q.x(), 0; if (const UStaticMeshSocket* Socket = GetSocketByName("JointNext")){
const Eigen::Matrix3d R = (w * w - q.dot(q)) * Eigen::Matrix3d::Identity() + 2 * q * q.transpose() + 2 * w * q_hat; if (NextJoint){
return R; NextJoint->FirstLocalPosition = ToEigen(Socket->RelativeLocation);
NextJoint->FirstRotateAxis = ToEigen(Socket->RelativeRotation.Vector());
}
}
} }
void ULink::BeginPlay(){
const FVector t = this->GetInertiaTensor(); void ULink::Update(const double H){
inertia_tensor = Eigen::Vector3d(t.X, t.Y, t.Z); const Vector3d ExtTransForce = Vector3d(0, 0, -9.81 * 100) * Mass;
const double M = this->CalculateMass(); Last_Position = Position;
Eigen::Vector3d v; Velocity += H * ExtTransForce / Mass;
v << 3, 5, 7; Position += H * Velocity;
UE_LOG(LogTemp, Log, TEXT("%f"), M); Last_Orientation = Orientation;
// Angle Velocity has no external contributor
Vector3d w = AngularVelocity;
Orientation += Quaterniond(0, w.x(), w.y(), w.z()) * Orientation * 0.5 * H;
Orientation.normalize();
}
void ULink::Integrate(const double H){
Velocity = (Position - Last_Position) / H;
Quaterniond DeltaOrientation = Orientation * Last_Orientation.inverse();
AngularVelocity = 2 * DeltaOrientation.vec() / H;
AngularVelocity = DeltaOrientation.w() >= 0 ? AngularVelocity : -AngularVelocity;
}
void ULink::UpdateVisualTransform(){
SetWorldLocation(FromEigen(Position));
SetWorldRotation(FromEigen(Orientation));
} }

@ -3,10 +3,13 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Joint.h"
#include "Components/StaticMeshComponent.h" #include "Components/StaticMeshComponent.h"
#include "Eigen/Dense" #include "Eigen/Dense"
#include "Link.generated.h" #include "Link.generated.h"
using namespace Eigen;
/** /**
* *
*/ */
@ -14,21 +17,41 @@ UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class PBDROBOTICS_API ULink : public UStaticMeshComponent class PBDROBOTICS_API ULink : public UStaticMeshComponent
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
Eigen::Vector3d CenterOfMass;
Eigen::Vector3d Position; // Properties in World space
Eigen::Vector3d Velocity;
Vector3d CenterOfMass;
Vector3d Position;
Vector3d Velocity;
double Mass; double Mass;
Eigen::Quaterniond Orientation; Quaterniond Orientation;
Eigen::Vector3d AngleVelocity; Vector3d AngularVelocity;
Eigen::Matrix3d Inertia; Matrix3d Inertia;
Vector3d Last_Position;
Quaterniond Last_Orientation;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UJoint* PrevJoint;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
UJoint* NextJoint;
void Update(const double H);
void Integrate(const double H);
void UpdateVisualTransform();
Matrix3d GetRotationMatrix() const;
void Setup();
private: private:
Eigen::Vector3d inertia_tensor; UPROPERTY(EditAnywhere)
Eigen::Matrix3d GetMomentOfInertia() const; bool IsBase = false;
Eigen::Matrix3d GetRotationMatrix() const;
Matrix3d Inertia_Tensor_Local;
Matrix3d GetMomentOfInertia() const;
protected: void SetupJoints() const;
virtual void BeginPlay() override; void SetupProperties();
}; };

@ -3,25 +3,38 @@
#include "Robot.h" #include "Robot.h"
// Sets default values ARobot::ARobot(){
ARobot::ARobot()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bCanEverTick = true;
} }
// Called when the game starts or when spawned void ARobot::BeginPlay(){
void ARobot::BeginPlay()
{
Super::BeginPlay(); Super::BeginPlay();
GetComponents<ULink>(Parts);
for (auto* Link : Parts) Link->Setup();
} }
// Called every frame void ARobot::Tick(const float DeltaTime){
void ARobot::Tick(float DeltaTime)
{
Super::Tick(DeltaTime); Super::Tick(DeltaTime);
constexpr int SubSteps = 10;
const double h = DeltaTime / SubSteps;
for (int i = 0; i < SubSteps; i++){
for (auto* Link : Parts) Link->Update(h);
SolvePositions();
for (auto* Link : Parts) Link->Integrate(h);
SolveVelocities();
}
for (auto* Link : Parts) Link->UpdateVisualTransform();
}
void ARobot::SolvePositions(){
} }
void ARobot::SolveVelocities(){
}

@ -3,6 +3,7 @@
#pragma once #pragma once
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Link.h"
#include "GameFramework/Actor.h" #include "GameFramework/Actor.h"
#include "Robot.generated.h" #include "Robot.generated.h"
@ -10,7 +11,6 @@ UCLASS()
class PBDROBOTICS_API ARobot : public AActor class PBDROBOTICS_API ARobot : public AActor
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
// Sets default values for this actor's properties // Sets default values for this actor's properties
ARobot(); ARobot();
@ -23,4 +23,10 @@ public:
// Called every frame // Called every frame
virtual void Tick(float DeltaTime) override; virtual void Tick(float DeltaTime) override;
private:
UPROPERTY()
TArray<ULink*> Parts;
void SolvePositions();
void SolveVelocities();
}; };

@ -0,0 +1,27 @@
#pragma once
#include "Eigen/Dense"
inline Vector3d ToEigen(const FVector V){
return Vector3d(V.X, V.Y, V.Z);
}
inline FVector FromEigen(const Vector3d V){
return FVector(V.x(), V.y(), V.z());
}
inline FQuat FromEigen(const Quaterniond Q){
return FQuat(Q.x(), Q.y(), Q.z(), Q.w());
}
inline Quaterniond operator* (const Quaterniond Q, const double D){
return Quaterniond(Q.w() * D, Q.x() * D, Q.y() * D, Q.z() * D);
}
inline Quaterniond operator+ (const Quaterniond Q1, const Quaterniond Q2){
return Quaterniond(Q1.w() + Q2.w(), Q1.x() + Q2.x(), Q1.y() + Q2.y(), Q1.z() + Q2.z());
}
inline Quaterniond operator+= (const Quaterniond Q1, const Quaterniond Q2){
return Q1 + Q2;
}
Loading…
Cancel
Save