Agrarsense
MovementSubscriber.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
7
11
12#include "ROSIntegration/Classes/ROSIntegrationGameInstance.h"
13#include <geometry_msgs/Twist.h>
14#include <std_msgs/String.h>
15
16#include "Async/Async.h"
17#include "AITypes.h"
18
19UMovementSubscriber::UMovementSubscriber()
20{
21 PrimaryComponentTick.bCanEverTick = false;
22}
23
24void UMovementSubscriber::BeginPlay()
25{
26 Super::BeginPlay();
27
28 CreateROSTopic();
29
30 UROSHandler* RosHandle = UAgrarsenseStatics::GetROSHandle(GetWorld());
31 if (RosHandle)
32 {
33 RosHandle->OnROSStateChanged.AddUniqueDynamic(this, &UMovementSubscriber::ROSBridgeStateChanged);
34 }
35}
36
37void UMovementSubscriber::OnUnregister()
38{
39 Super::OnUnregister();
40
41 DestroyROSTopic();
42
43 UROSHandler* RosHandle = UAgrarsenseStatics::GetROSHandle(GetWorld());
44 if (RosHandle)
45 {
46 RosHandle->OnROSStateChanged.RemoveDynamic(this, &UMovementSubscriber::ROSBridgeStateChanged);
47 }
48}
49
50void UMovementSubscriber::ROSBridgeStateChanged(EROSState rosState)
51{
52 switch (rosState)
53 {
55 CreateROSTopic();
56 break;
57
59 DestroyROSTopic();
60 break;
61 }
62}
63
64void UMovementSubscriber::CreateROSTopic()
65{
66 if (MovementTopic)
67 {
68 return;
69 }
70
71 UROSIntegrationGameInstance* ROSInstance = UAgrarsenseStatics::GetROSGameInstance(GetWorld());
72
73 if (ROSInstance && ROSInstance->IsROSConnected())
74 {
75 FString VehicleName = "Vehicle";
76
77 // Get this Actor this component is attached to
78 AActor* OwnerActor = GetOwner();
79 if (OwnerActor)
80 {
81 // Try to cast the owning actor into AVehicle and
82 // get its ID and use the ID as the vehicle name
83 AVehicle* VehiclePtr = Cast<AVehicle>(OwnerActor);
84 if (VehiclePtr)
85 {
86 VehicleName = VehiclePtr->GetActorID_Implementation();
87 }
88 else
89 {
90 VehicleName = OwnerActor->GetName();
91 }
92 }
93
94 MovementTopic = NewObject<UTopic>(UTopic::StaticClass());
95 MovementTopic->Init(ROSInstance->ROSIntegrationCore, FString::Printf(TEXT("/agrarsense/in/vehicles/%s/movement"), *VehicleName), TEXT("std_msgs/String"));
96 MovementTopic->Advertise();
97
98 std::function<void(TSharedPtr<FROSBaseMsg>)> SubscribeCallback = [this](TSharedPtr<FROSBaseMsg> msg) -> void
99 {
100 //auto Concrete = StaticCastSharedPtr<ROSMessages::geometry_msgs::Twist>(msg);
101 auto Concrete = StaticCastSharedPtr<ROSMessages::std_msgs::String>(msg);
102 if (Concrete.IsValid())
103 {
104 // TempResult[0] = Throttle, TempResult[1] = Break, TempResult[2] = Steering
105 TArray<FString> TempResult;
106 Concrete->_Data.ParseIntoArray(TempResult, TEXT(","));
107
108 if (TempResult.Num() < 3)
109 return;
110
111 FMessageParser Movement;
112 Movement.Throttle = TempResult[0].IsNumeric() ? FMath::Clamp(FCString::Atof(*TempResult[0]), -1 , 1) : 0.0f;
113 Movement.Break = TempResult[1].IsNumeric() ? FMath::Clamp(FCString::Atof(*TempResult[1]), 0, 1) : 0.0f;
114 Movement.Steering = TempResult[2].IsNumeric() ? FMath::Clamp(FCString::Atof(*TempResult[2]), -90, 90) : 0.0f;
115
116 AsyncTask(ENamedThreads::GameThread, [this, Movement]()
117 {
118 OnMessageReceived.Broadcast(Movement);
119 });
120
121 }
122 return;
123 };
124
125 MovementTopic->Subscribe(SubscribeCallback);
126 }
127}
128
129void UMovementSubscriber::DestroyROSTopic()
130{
131 if (MovementTopic)
132 {
133 MovementTopic->Unadvertise();
134 MovementTopic->Unsubscribe();
135 MovementTopic->MarkAsDisconnected();
136 MovementTopic->ConditionalBeginDestroy();
137 MovementTopic = nullptr;
138 }
139}
EROSState
Definition: ROSState.h:16
virtual FString GetActorID_Implementation() const override
Definition: Vehicle.h:203
static UROSIntegrationGameInstance * GetROSGameInstance(const UObject *WorldContextObject)
static UROSHandler * GetROSHandle(const UObject *WorldContextObject)
FROSDelegate_ROState OnROSStateChanged
Definition: ROSHandler.h:81