Agrarsense
Sensor.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 "Sensor.h"
7#include "SensorManager.h"
8#include "SemanticColors.h"
9
14
15#include "Kismet/GameplayStatics.h"
16#include "TimerManager.h"
17#include "UObject/Class.h"
18
19TArray<TWeakObjectPtr<UPrimitiveComponent>> ASensor::ComponentsToHide;
20FPrimitiveAdded ASensor::OnPrimitiveAdded;
21
22ASensor::ASensor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
23{
24 RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("SceneRoot"));
25}
26
28{
29 Super::BeginPlay();
30
31 UWorld* World = GetWorld();
32
34 if (ROSHandler)
35 {
36 // Subscribe to ROS changed event
37 ROSHandler->OnROSStateChanged.AddUniqueDynamic(this, &ASensor::ROSBridgeStateChanged);
38 }
39
41 if (ROSInstance)
42 {
43 // Check if ROS is connected at BeginPlay
44 ROSConnected = ROSInstance->IsROSConnected();
45 }
46
47 // Delay logging sensor information message so each sensor have time setup fully.
48 FTimerHandle Handle;
49 World->GetTimerManager().SetTimer(Handle, FTimerDelegate::CreateLambda([this]
50 {
51 if (IsValid(this))
52 {
53 FString Message = FString("Spawned ") + GetActorInformation_Implementation();
54 SimulatorLog::Log(Message);
55 }
56 }), 0.150f, false);
57
59}
60
61void ASensor::EndPlay(const EEndPlayReason::Type EndPlayReason)
62{
63 // Broadcast that this sensor will be destroyed
64 OnSensorDestroy.Broadcast(this);
65
67
68 Super::EndPlay(EndPlayReason);
69
70 UROSHandler* ROSHandler = UAgrarsenseStatics::GetROSHandle(GetWorld());
71 if (ROSHandler)
72 {
73 ROSHandler->OnROSStateChanged.RemoveDynamic(this, &ASensor::ROSBridgeStateChanged);
74 }
75
76 FString Sensor = UEnum::GetDisplayValueAsText(GetSensorType()).ToString();
77 FString ID = GetSensorIdentifier();
78 FString Message = FString::Printf(TEXT("Destroyed %s sensor with ID: %s"), *Sensor, *ID);
79 SimulatorLog::Log(Message);
80
81 if (EndPlayReason == EEndPlayReason::EndPlayInEditor
82 || EndPlayReason == EEndPlayReason::Quit)
83 {
84 for (auto& WeakComponentPtr : ComponentsToHide)
85 {
86 WeakComponentPtr.Reset();
87 }
88 ComponentsToHide.Empty();
89 }
90
91 // Destroy all Actors that are attached to this sensor (Sensor model for example)
92 TArray<AActor*> AttachedActors;
93 GetAttachedActors(AttachedActors);
94 for (AActor* Actor : AttachedActors)
95 {
96 if (Actor)
97 {
98 Actor->Destroy();
99 }
100 }
101
102 ROSInstance = nullptr;
103
104 if (LogFile)
105 {
106 LogFile->Destroy();
107 LogFile = nullptr;
108 }
109
111}
112
113FString ASensor::ExportToJsonFile(const FString& FileName)
114{
115 return USimulatorJsonExporter::ExportSensorToJSON(FileName, this);
116}
117
119{
120 switch (ROSState)
121 {
123 ROSConnected = true;
125 break;
126
128 ROSConnected = false;
130 break;
131 }
132}
133
135{
136 if (ROSTopic)
137 {
138 ROSTopic->Unadvertise();
139 ROSTopic->Unsubscribe();
140 ROSTopic->MarkAsDisconnected();
141 ROSTopic->ConditionalBeginDestroy();
142 ROSTopic = nullptr;
143 }
144}
145
147{
148 if (!SendDataToROS
149 || ROSTopic
150 || !ROSInstance
151 || !IsROSConnected())
152 {
153 return;
154 }
155
156 FString MessageType;
157 ESensorTypes SensorType = GetSensorType();
158
159 switch (SensorType)
160 {
163 MessageType = "sensor_msgs/PointCloud2";
164 break;
165
170 case ESensorTypes::DVSCamera: // DVS Camera should override this.
171 MessageType = "sensor_msgs/Image";
172 break;
173
175 MessageType = "geometry_msgs/Transform";
176 break;
177
180 MessageType = "std_msgs/String";
181 break;
182
183 default:
184 FString SensorNameString = UEnumUtilities::ConvertSensorTypeToString(SensorType);
185 UE_LOG(LogTemp, Warning, TEXT("Unhandled ROS sensor message creation for sensor: %s"), *SensorNameString);
186 break;
187 }
188
189 FString TopicName = FString::Printf(TEXT("/agrarsense/out/sensors/%s"), *GetSensorIdentifier());
190
191 ROSTopic = NewObject<UTopic>(UTopic::StaticClass());
192 if (ROSTopic)
193 {
194 ROSTopic->Init(ROSInstance->ROSIntegrationCore, TopicName, MessageType);
195 ROSTopic->Advertise();
196 }
197
198 FString Message = FString::Printf(TEXT("%s sensor created ROS topic. Name: '%s' MessageType: '%s' "), *GetSensorName(), *TopicName, *MessageType);
199 SimulatorLog::Log(Message);
200}
201
203{
204 if (FileSavePath.IsEmpty())
205 {
206 FString DataLocation = UAgrarsensePaths::GetDataFolder();
207 FString UnixTimeStamp = FString::FromInt(FDateTime::Now().ToUnixTimestamp());
208 FileSavePath = DataLocation + GetSensorIdentifier() + "_" + UnixTimeStamp + "/";
209 }
210}
211
213{
214 if (IsValid(LogFile))
215 {
216 // File has already been created, return
217 return;
218 }
219
220 FLogFileSettings Settings;
223 Settings.QueueLength = 10;
224 Settings.KeepFileOpen = false;
225
226 LogFile = NewObject<ULogFile>(ULogFile::StaticClass());
227 if (LogFile)
228 {
229 // FileName is SensorName_ID_UnixTimeStamp.txt
230 FString UnixTimeStamp = FString::FromInt(FDateTime::Now().ToUnixTimestamp());
231
232 FString ActorID = GetActorID_Implementation();
233
234 // Temp fix, Remove all "/" from ActorID
235 ActorID.ReplaceInline(TEXT("/"), TEXT(""), ESearchCase::IgnoreCase);
236
237 FString FileName = FString::Printf(TEXT("%s_%s_%s"), *GetSensorName(), *ActorID, *UnixTimeStamp);
238 LogFile->Create(FileName, Settings);
239 }
240}
241
242void ASensor::WriteToLogFile(const FString& Message)
243{
244 if (!IsValid(LogFile) && IsValid(this))
245 {
247 }
248
249 if (IsValid(LogFile))
250 {
251 LogFile->Write(Message);
252 }
253}
254
255void ASensor::HideComponentForAllCameras(UPrimitiveComponent* PrimitiveComponent)
256{
257 if (PrimitiveComponent)
258 {
259 TWeakObjectPtr<UPrimitiveComponent> Component(PrimitiveComponent);
260 ComponentsToHide.Add(Component);
261 OnPrimitiveAdded.Broadcast(PrimitiveComponent);
262 }
263}
264
265TMap<FString, FColor> ASensor::GetSemanticColors()
266{
268}
EROSState
Definition: ROSState.h:16
ESensorTypes
Definition: SensorTypes.h:15
@ SemanticSegmentationCamera
static TArray< TWeakObjectPtr< UPrimitiveComponent > > ComponentsToHide
Definition: Sensor.h:386
virtual void DestroyROSTopic()
Definition: Sensor.cpp:134
virtual void CreateLogFile()
Definition: Sensor.cpp:212
void ROSBridgeStateChanged(EROSState ROSState)
Definition: Sensor.cpp:118
UROSIntegrationGameInstance * ROSInstance
Definition: Sensor.h:352
static void HideComponentForAllCameras(UPrimitiveComponent *PrimitiveComponent)
Definition: Sensor.cpp:255
virtual void BeginPlay() override
Definition: Sensor.cpp:27
FSensorDestroy OnSensorDestroy
Definition: Sensor.h:269
static FPrimitiveAdded OnPrimitiveAdded
Definition: Sensor.h:354
FString GetSensorIdentifier() const
Definition: Sensor.h:74
UTopic * ROSTopic
Definition: Sensor.h:341
virtual void CreateDataSavePath()
Definition: Sensor.cpp:202
FString GetSensorName() const
Definition: Sensor.h:95
virtual ESensorTypes GetSensorType() const
Definition: Sensor.h:64
ULogFile * LogFile
Definition: Sensor.h:347
FString ExportToJsonFile(const FString &FileName)
Definition: Sensor.cpp:113
virtual FString GetActorID_Implementation() const override
Definition: Sensor.h:207
bool IsROSConnected() const
Definition: Sensor.h:192
bool SendDataToROS
Definition: Sensor.h:344
bool ROSConnected
Definition: Sensor.h:384
FString FileSavePath
Definition: Sensor.h:349
void WriteToLogFile(const FString &Message)
Definition: Sensor.cpp:242
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
Definition: Sensor.cpp:61
virtual void CreateROSTopic()
Definition: Sensor.cpp:146
virtual FString GetActorInformation_Implementation() const override
Definition: Sensor.h:217
ASensor(const FObjectInitializer &ObjectInitializer)
Definition: Sensor.cpp:22
static TMap< FString, FColor > GetSemanticColors()
Definition: Sensor.cpp:265
static void Log(const FString &Message, bool LogToTextFile=true, bool LogToROS=true)
static FString GetDataFolder()
static UROSIntegrationGameInstance * GetROSGameInstance(const UObject *WorldContextObject)
static UROSHandler * GetROSHandle(const UObject *WorldContextObject)
static FString ConvertSensorTypeToString(ESensorTypes Sensortype)
void Destroy()
Definition: LogFile.cpp:170
void Write(const FString &Text)
Definition: LogFile.cpp:119
void Create(const FString &FileNameWithoutExtension, FLogFileSettings Settings)
Definition: LogFile.cpp:40
FROSDelegate_ROState OnROSStateChanged
Definition: ROSHandler.h:81
static TMap< FString, FColor > GetSemanticColors()
static void AddSensor(ASensor *SensorPtr)
static void RemoveSensor(ASensor *SensorPtr)
static FString ExportSensorToJSON(const FString &FileName, ASensor *Sensor)
bool KeepFileOpen
Definition: LogFile.h:42
FFileWriteOptions FileWriteOptions
Definition: LogFile.h:45
int32 QueueLength
Definition: LogFile.h:48
FFileCreationOptions FileCreationOptions
Definition: LogFile.h:36