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{
45 Super::EndPlay(EndPlayReason);
46
48
49 GnssMessageString.Reset();
50 TransformMessage.Reset();
51 Target.Reset();
52}
53
55{
56 Super::CreateROSTopic();
57
58 GeoReferencingSystem = AGeoReferencingSystem::GetGeoReferencingSystem(GetWorld());
59
60 // If map has been georeferenced, create gnss topic.
62 {
63 FString TopicName = FString::Printf(TEXT("/agrarsense/out/sensors/%s"), *GetSensorIdentifier());
64 int32 LastSlashIndex = TopicName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromEnd);
65 if (LastSlashIndex != INDEX_NONE)
66 {
67 TopicName = TopicName.Left(LastSlashIndex) + TEXT("/gnss");
68 }
69 else
70 {
71 TopicName += TEXT("/gnss");
72 }
73
74 GnssTopic = NewObject<UTopic>(UTopic::StaticClass());
75 if (GnssTopic)
76 {
77 GnssTopic->Init(ROSInstance->ROSIntegrationCore, TopicName, TEXT("std_msgs/String"));
78 GnssTopic->Advertise();
79 }
80 }
81}
82
84{
85 Super::DestroyROSTopic();
86
87 if (GnssTopic)
88 {
89 GnssTopic->Unadvertise();
90 GnssTopic->Unsubscribe();
91 GnssTopic->MarkAsDisconnected();
92 GnssTopic->ConditionalBeginDestroy();
93 GnssTopic = nullptr;
94 }
95}
96
97void ATransformSensor::TickParallel(float DeltaTime)
98{
99 AActor* TargetActor = Target.Get();
100 if (!CanSimulateSensor() || !TargetActor)
101 {
102 return;
103 }
104
105 FTransform CurrentTransform = TargetActor->GetTransform();
106 FVector CurrentPos = CurrentTransform.GetLocation();
107 FQuat CurrentRot = CurrentTransform.GetRotation();
108
109 if (CurrentPos != PreviousActorPosition)
110 {
111 // Send transform data to ROS topic,
112 // this is done frequently but this should be quite fast and
113 // should give precise actor's current location and rotation in the World.
114 PreviousActorPosition = CurrentPos;
115
116 if (IsROSConnected())
117 {
118 SendTransformDataToROS(CurrentPos, CurrentRot);
119 SendGnssDataToROS(CurrentPos);
120 }
121 }
122}
123
124void ATransformSensor::SendTransformDataToROS(const FVector& Translation, const FQuat& Rotation)
125{
126 UTopic* Topic = GetROSTopic();
127 if (Topic && TransformMessage.IsValid())
128 {
129 TransformMessage->translation = Translation;
130 TransformMessage->rotation = Rotation;
131 Topic->Publish(TransformMessage);
132 }
133}
134
135void ATransformSensor::SendGnssDataToROS(const FVector& ActorPosition)
136{
138 {
139 // Convert Actor position to FGeographicCoordinates
140 FGeographicCoordinates GeographicCoordinates = UCoordinateConversionUtilities::UnrealToGeographicCoordinates(GeoReferencingSystem, ActorPosition);
141
142 double Latitude = GeographicCoordinates.Latitude;
143 double Longitude = GeographicCoordinates.Longitude;
144 double Altitude = GeographicCoordinates.Altitude;
145
146 // Create gnss string and send the message to the created ROS topic
147 FString GnssDataString = FString::Printf(TEXT("%f, %f, %f"), Latitude, Longitude, Altitude);
148 GnssMessageString->_Data = GnssDataString;
150 }
151}
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
void SetSimulateSensor(bool SimulateSensor)
Definition: Sensor.h:151
UTopic * GetROSTopic() const
Definition: Sensor.h:141
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)