Agrarsense
CollisionSensor.cpp
Go to the documentation of this file.
1// Copyright (c) 2023 FrostBit Software Lab at the Lapland University of Applied Sciences
2//
3// This work is licensed under the terms of the MIT license.
4// For a copy, see <https://opensource.org/licenses/MIT>.
5
6#include "CollisionSensor.h"
7#include "Collision.h"
8
11
12ACollisionSensor::ACollisionSensor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
13{
14 PrimaryActorTick.bCanEverTick = false;
15}
16
17void ACollisionSensor::Init(FCollisionSensorParameters CollisionSensorParameters, bool SimulateSensor)
18{
19 SetSimulateSensor(SimulateSensor);
20
21 if (CollisionSensorParameters.OwningActor)
22 {
23 CurrentOwner = CollisionSensorParameters.OwningActor;
24 PrimitiveComponent = CollisionSensorParameters.PrimitiveComponent;
25
26 if (CollisionSensorParameters.UseActorCollision && CurrentOwner.Get())
27 {
28 CurrentOwner->OnActorHit.AddDynamic(this, &ACollisionSensor::OnActorHit);
29 }
30 else if (CollisionSensorParameters.PrimitiveComponent)
31 {
32 PrimitiveComponent->OnComponentHit.AddDynamic(this, &ACollisionSensor::OnComponentHit);
33 }
34
35 AttachToActor(CurrentOwner.Get(), FAttachmentTransformRules::KeepWorldTransform);
36 }
37
38 CollisionMessage = MakeShared<ROSMessages::std_msgs::String>();
39
42}
43
45{
46 Super::BeginPlay();
47}
48
49void ACollisionSensor::EndPlay(const EEndPlayReason::Type EndPlayReason)
50{
51 Super::EndPlay(EndPlayReason);
52
53 if (CurrentOwner.Get())
54 {
55 CurrentOwner->OnActorHit.RemoveDynamic(this, &ACollisionSensor::OnActorHit);
56 CurrentOwner.Reset();
57 }
58
60 {
61 PrimitiveComponent->OnComponentHit.RemoveDynamic(this, &ACollisionSensor::OnComponentHit);
62 PrimitiveComponent = nullptr;
63 }
64
66 CollisionMessage.Reset();
67}
68
69void ACollisionSensor::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
70{
71 if (!CanSimulateSensor() || !OtherActor || !CurrentOwner.Get())
72 {
73 return;
74 }
75
76 NormalImpulse *= 1e-2;
77 if (NormalImpulse.Size() > 0.3f)
78 {
79 CollisionData Collisiondata =
80 {
81 CurrentOwner.Get(),
82 OtherActor,
83 CurrentOwner->GetName(),
84 OtherActor->GetName(),
85 NormalImpulse
86 };
87
88 FString CollisionDataString = CollsionDataToString(Collisiondata);
89 SendCollisionData(CollisionDataString);
90 WriteToLogFile(CollisionDataString);
91 }
92}
93
94void ACollisionSensor::OnActorHit(AActor* Actor, AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit)
95{
96 if (!CanSimulateSensor() || !Actor || !OtherActor)
97 {
98 return;
99 }
100
101 NormalImpulse *= 1e-2;
102 if (NormalImpulse.Size() > 200)
103 {
104 CollisionData Collisiondata =
105 {
106 Actor,
107 OtherActor,
108 Actor->GetName(),
109 OtherActor->GetName(),
110 NormalImpulse
111 };
112
113 FString CollisionDataString = CollsionDataToString(Collisiondata);
114 SendCollisionData(CollisionDataString);
115 WriteToLogFile(CollisionDataString);
116 }
117}
118
120{
121 auto Quote = [](FString S)
122 {
123 S.ReplaceInline(TEXT("\""), TEXT("\\\""));
124 return FString::Printf(TEXT("%s"), *S);
125 };
126
127
128 FString ID;
129 FVector Location;
130
131 if (Data.OtherActorPtr)
132 {
133 ID = TryGetID(Data.OtherActorPtr);
134 Location = Data.ActorPtr->GetActorLocation();
135 }
136
137 auto NormalImpulse = Data.NormalImpulse;
138 const FString ImpulseStr = FString::Printf(TEXT("%.2f,%.2f,%.2f"), NormalImpulse.X, NormalImpulse.Y, NormalImpulse.Z);
139 const double ImpulseMag = Data.NormalImpulse.Size();
140 const FString Ts = CreateTimeStampString();
141
142 return FString::Printf(
143 TEXT("actor=%s other_actor=%s other_actor_id=%s other_actor_location=%.2f,%.2f,%.2f impulse_strength=%s impulse_magnitude=%.2f timestamp=%s"),
144 *Quote(Data.Actor),
145 *Quote(Data.OtherActor),
146 *Quote(ID),
147 Location.X, Location.Y, Location.Z,
148 *ImpulseStr,
149 ImpulseMag,
150 *Quote(Ts));
151}
152
153FString ACollisionSensor::TryGetID(AActor* Actor) const
154{
155 FString ID;
156
157 if (Actor && Actor->GetClass()->ImplementsInterface(UActorInformation::StaticClass()))
158 {
159 if (Actor->Implements<UActorInformation>())
160 {
161 ID = IActorInformation::Execute_GetActorID(Actor);
162 }
163 }
164
165 return ID;
166}
167
168void ACollisionSensor::SendCollisionData(const FString& CollisionDataString)
169{
170 UTopic* Topic = GetROSTopic();
171 if (IsROSConnected() && CollisionMessage.IsValid() && Topic)
172 {
173 CollisionMessage->_Data = CollisionDataString;
174 Topic->Publish(CollisionMessage);
175 }
176}
177
179{
180 if (!FileSavePath.IsEmpty())
181 {
182 return;
183 }
184
185 const FString DataLocation = UAgrarsensePaths::GetDataFolder();
186
187 // Default save path
188 FileSavePath = DataLocation + GetActorID_Implementation() + "/";
189
190 if (AVehicle* AttachedVehicle = IsAttachedToVehicle())
191 {
192 // If sensor is attached to vehicle, save data to vehicle folder
193 FileSavePath = DataLocation + AttachedVehicle->GetActorID_Implementation();
194 }
195}
196
198{
199 if (IsValid(LogFile))
200 {
201 // File has already been created, return
202 return;
203 }
204
206
207 FLogFileSettings Settings;
210 Settings.QueueLength = MAX_int32;
211 Settings.KeepFileOpen = false;
212 Settings.Timestamp = false;
213 Settings.OverrideFilePath = true;
214 Settings.FilePath = FileSavePath;
215
216 UE_LOG(LogTemp, Warning, TEXT("FileSavePath %s"), *FileSavePath);
217
218 LogFile = NewObject<ULogFile>(ULogFile::StaticClass());
219 if (IsValid(LogFile))
220 {
221 FString Prefix;
222 if (AVehicle* AttachedVehicle = IsAttachedToVehicle())
223 {
224 Prefix = AttachedVehicle->GetActorID_Implementation();
225 }
226 FString FileName = Prefix.IsEmpty() ? TEXT("collision") : Prefix + TEXT("_collision");
227
228 LogFile->Create(FileName, Settings);
229 }
230}
void SendCollisionData(const FString &CollisionDataString)
void Init(FCollisionSensorParameters CollisionSensorParameters, bool SimulateSensor=true)
void OnComponentHit(UPrimitiveComponent *HitComponent, AActor *OtherActor, UPrimitiveComponent *OtherComp, FVector NormalImpulse, const FHitResult &Hit)
UPrimitiveComponent * PrimitiveComponent
FString CollsionDataToString(const CollisionData &Data)
FString TryGetID(AActor *Actor) const
TSharedPtr< ROSMessages::std_msgs::String > CollisionMessage
FCollisionSensorParameters Parameters
ACollisionSensor(const FObjectInitializer &ObjectInitializer)
virtual void BeginPlay() override
void CreateLogFile() override
void CreateDataSavePath() override
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
void OnActorHit(AActor *Actor, AActor *OtherActor, FVector NormalImpulse, const FHitResult &Hit)
TWeakObjectPtr< AActor > CurrentOwner
bool CanSimulateSensor() const
Definition: Sensor.h:170
void SetSimulateSensor(bool SimulateSensor)
Definition: Sensor.h:160
UTopic * GetROSTopic() const
Definition: Sensor.h:150
AVehicle * IsAttachedToVehicle() const
Definition: Sensor.cpp:159
ULogFile * LogFile
Definition: Sensor.h:367
virtual FString GetActorID_Implementation() const override
Definition: Sensor.h:216
FString CreateTimeStampString() const
Definition: Sensor.cpp:330
FString FileSavePath
Definition: Sensor.h:372
void WriteToLogFile(const FString &Message)
Definition: Sensor.cpp:302
FORCEINLINE bool IsROSConnected() const
Definition: Sensor.h:201
virtual void CreateROSTopic()
Definition: Sensor.cpp:197
static FString GetDataFolder()
void Create(const FString &FileNameWithoutExtension, FLogFileSettings Settings)
Definition: LogFile.cpp:40
AActor * OtherActorPtr
FString OtherActor
FVector NormalImpulse
AActor * ActorPtr
UPrimitiveComponent * PrimitiveComponent
bool KeepFileOpen
Definition: LogFile.h:42
bool Timestamp
Definition: LogFile.h:39
FString FilePath
Definition: LogFile.h:54
FFileWriteOptions FileWriteOptions
Definition: LogFile.h:45
int32 QueueLength
Definition: LogFile.h:48
bool OverrideFilePath
Definition: LogFile.h:51
FFileCreationOptions FileCreationOptions
Definition: LogFile.h:36