Agrarsense
TransformSensor.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 "TransformSensor.h"
7
9
10#include "GeoReferencingSystem.h"
11#include "Kismet/GameplayStatics.h"
12#include "Engine/World.h"
13
14ATransformSensor::ATransformSensor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
15{
16 // TickManager handles this Actor ticking
17 PrimaryActorTick.bCanEverTick = false;
18}
19
20void ATransformSensor::Init(AActor* TransformActor, bool SimulateSensor)
21{
22 SetSimulateSensor(SimulateSensor);
23 Target = TransformActor;
24
25 ROSMessages::geometry_msgs::Transform transformMsg;
26 TransformMessage = MakeShared<ROSMessages::geometry_msgs::Transform>(transformMsg);
27
28 GnssMessageString = MakeShared<ROSMessages::std_msgs::String>();
29
31}
32
34{
35 Super::BeginPlay();
36
37 SetActorEnableCollision(false);
38 PreviousActorPosition = GetActorLocation();
39
40 TickEntry = ATickManager::AddTick(this, BindTick(this, &ATransformSensor::TickParallel), ETickType::LateTickParallel);
41}
42
43void ATransformSensor::EndPlay(const EEndPlayReason::Type EndPlayReason)
44{
46
48 GnssMessageString.Reset();
49 TransformMessage.Reset();
50 Target.Reset();
51
52 Super::EndPlay(EndPlayReason);
53}
54
56{
57 Super::CreateROSTopic();
58
59 GeoReferencingSystem = AGeoReferencingSystem::GetGeoReferencingSystem(GetWorld());
60
61 // If map has been georeferenced, create gnss topic.
63 {
64 FString TopicName = FString::Printf(TEXT("/agrarsense/out/sensors/%s"), *GetSensorIdentifier());
65 int32 LastSlashIndex = TopicName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromEnd);
66 if (LastSlashIndex != INDEX_NONE)
67 {
68 TopicName = TopicName.Left(LastSlashIndex) + TEXT("/gnss");
69 }
70 else
71 {
72 TopicName += TEXT("/gnss");
73 }
74
75 GnssTopic = NewObject<UTopic>(UTopic::StaticClass());
76 if (GnssTopic)
77 {
78 GnssTopic->Init(ROSInstance->ROSIntegrationCore, TopicName, TEXT("std_msgs/String"));
79 GnssTopic->Advertise();
80 }
81 }
82}
83
85{
86 if (GnssTopic)
87 {
88 GnssTopic->Unadvertise();
89 GnssTopic->Unsubscribe();
90 GnssTopic->MarkAsDisconnected();
91 GnssTopic->ConditionalBeginDestroy();
92 GnssTopic = nullptr;
93 }
94
95 if (ROSTopic)
96 {
97 ROSTopic->Unadvertise();
98 ROSTopic->Unsubscribe();
99 ROSTopic->MarkAsDisconnected();
100 ROSTopic->ConditionalBeginDestroy();
101 ROSTopic = nullptr;
102 }
103}
104
106{
107 AActor* TargetActor = Target.Get();
108 if (!CanSimulateSensor() || !TargetActor)
109 {
110 return;
111 }
112
113 FTransform CurrentTransform = TargetActor->GetTransform();
114 FVector CurrentPos = CurrentTransform.GetLocation();
115 FQuat CurrentRot = CurrentTransform.GetRotation();
116
117 if (CurrentPos != PreviousActorPosition)
118 {
119 // Send transform data to ROS topic,
120 // this is done frequently but this should be quite fast and
121 // should give precise actor's current location and rotation in the World.
122 PreviousActorPosition = CurrentPos;
123
124 if (IsROSConnected())
125 {
126 SendTransformDataToROS(CurrentPos, CurrentRot);
127 SendGnssDataToROS(CurrentPos);
128 }
129 }
130}
131
132void ATransformSensor::SendTransformDataToROS(const FVector& Translation, const FQuat& Rotation)
133{
134 UTopic* Topic = GetROSTopic();
135 if (Topic && TransformMessage.IsValid())
136 {
137 TransformMessage->translation = Translation;
138 TransformMessage->rotation = Rotation;
139 Topic->Publish(TransformMessage);
140 }
141}
142
143void ATransformSensor::SendGnssDataToROS(const FVector& ActorPosition)
144{
146 {
147 // Convert Actor position to FGeographicCoordinates
148 FGeographicCoordinates GeographicCoordinates = UCoordinateConversionUtilities::UnrealToGeographicCoordinates(GeoReferencingSystem, ActorPosition);
149
150 double Latitude = GeographicCoordinates.Latitude;
151 double Longitude = GeographicCoordinates.Longitude;
152 double Altitude = GeographicCoordinates.Altitude;
153
154 // Create gnss string and send the message to the created ROS topic
155 FString GnssDataString = FString::Printf(TEXT("%f, %f, %f"), Latitude, Longitude, Altitude);
156 GnssMessageString->_Data = GnssDataString;
158 }
159}
static auto BindTick(ObjectType *Object, FunctionType Function)
Definition: TickManager.h:182
UROSIntegrationGameInstance * ROSInstance
Definition: Sensor.h:352
bool CanSimulateSensor() const
Definition: Sensor.h:161
FString GetSensorIdentifier() const
Definition: Sensor.h:74
UTopic * ROSTopic
Definition: Sensor.h:341
void SetSimulateSensor(bool SimulateSensor)
Definition: Sensor.h:151
UTopic * GetROSTopic() const
Definition: Sensor.h:141
FORCEINLINE bool IsROSConnected() const
Definition: Sensor.h:192
static void RemoveTick(FTickEntry TickEntry)
Definition: TickManager.cpp:90
static FTickEntry AddTick(UObject *Object, std::function< void(float)> Function, ETickType Type)
Definition: TickManager.cpp:55
void SendTransformDataToROS(const FVector &Translation, const FQuat &Rotation)
virtual void BeginPlay() override
TSharedPtr< ROSMessages::std_msgs::String > GnssMessageString
TSharedPtr< ROSMessages::geometry_msgs::Transform > TransformMessage
void SendGnssDataToROS(const FVector &ActorPosition)
virtual void CreateROSTopic() override
FVector PreviousActorPosition
TWeakObjectPtr< AActor > Target
virtual void DestroyROSTopic() override
AGeoReferencingSystem * GeoReferencingSystem
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override
void Init(AActor *TransformActor, bool SimulateSensor=true)
FTickEntry TickEntry
void TickParallel(float DeltaTime)
ATransformSensor(const FObjectInitializer &ObjectInitializer)
static FGeographicCoordinates UnrealToGeographicCoordinates(AGeoReferencingSystem *GeoReferencingSystem, const FVector &Position)