31 #include "HAL/UnrealMemory.h"
33 #include "Kismet/GameplayStatics.h"
35 #include "Kismet/KismetSystemLibrary.h"
37 #include "UObject/Object.h"
43 #include "builtin_interfaces/msg/detail/time__struct.h"
45 #include "geometry_msgs/msg/quaternion.h"
47 #include "geometry_msgs/msg/transform.h"
49 #include "geometry_msgs/msg/vector3.h"
51 #include "rosidl_runtime_c/string.h"
53 #include "rosidl_runtime_c/string_functions.h"
55 #include "rosidl_runtime_c/u16string_functions.h"
57 #include "std_msgs/msg/string.h"
65 #include "rcl/graph.h"
69 #include "rcl_action/wait.h"
71 #include "rclc/rclc.h"
75 #include "rclcUtilities.generated.h"
79 DECLARE_LOG_CATEGORY_EXTERN(LogROS2, Log, All);
83 static TAutoConsoleVariable<int32> CVarRclUERcsSoftCheck(
85 TEXT(
"RCLUE.RCSOFTCHECK"),
89 TEXT(
"Exit UE with rcl function error or not.\n")
91 TEXT(
"<=0: Continue without exiting UE even with rcl functions return error code.")
93 TEXT(
" 1: Exit UE with rcl functions error code.)\n"),
95 ECVF_Scalability | ECVF_RenderThreadSafe);
101 #define RCSOFTCHECK(fn) \
105 rcl_ret_t temp_rc = fn; \
107 if ((temp_rc != RCL_RET_OK)) \
111 UE_LOG_WITH_INFO(LogTemp, \
115 TEXT(
"Failed status on line %d (function %s): %d. Continuing."), \
119 *FString(__FUNCTION__), \
123 static
const auto CVar = IConsoleManager::Get().FindConsoleVariable(TEXT(
"RCLUE.RCSOFTCHECK")); \
125 if (CVar->GetInt()) \
129 check(temp_rc == 0); \
213 RMW_QOS_POLICY_RELIABILITY_RELIABLE,
215 RMW_QOS_POLICY_DURABILITY_VOLATILE,
217 RMW_QOS_DEADLINE_DEFAULT,
219 RMW_QOS_LIFESPAN_DEFAULT,
221 RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
223 RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT,
235 RMW_QOS_POLICY_RELIABILITY_RELIABLE,
237 RMW_QOS_POLICY_DURABILITY_VOLATILE,
239 RMW_QOS_DEADLINE_DEFAULT,
241 RMW_QOS_LIFESPAN_DEFAULT,
243 RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
245 RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT,
257 RMW_QOS_POLICY_RELIABILITY_RELIABLE,
259 RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
261 RMW_QOS_DEADLINE_DEFAULT,
263 RMW_QOS_LIFESPAN_DEFAULT,
265 RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
267 RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT,
279 RMW_QOS_POLICY_RELIABILITY_RELIABLE,
281 RMW_QOS_POLICY_DURABILITY_VOLATILE,
283 RMW_QOS_DEADLINE_DEFAULT,
285 RMW_QOS_LIFESPAN_DEFAULT,
287 RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
289 RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT,
301 RMW_QOS_POLICY_RELIABILITY_RELIABLE,
303 RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
305 RMW_QOS_DEADLINE_DEFAULT,
307 RMW_QOS_LIFESPAN_DEFAULT,
309 RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
311 RMW_QOS_LIVELINESS_LEASE_DURATION_DEFAULT,
319 static const TMap<UROS2QoS, rmw_qos_profile_t>
QoS_LUT = {{UROS2QoS::Default, rmw_qos_profile_default},
406 FTimerDelegate Delegate;
410 FTimerDelegate TimerDelegate;
433 GetWorld()->GetTimerManager().ClearTimer(
TimerHandle);
441 void SetTimer(FTimerDelegate
const& InDelegate,
float InRate)
449 Delegate = InDelegate;
457 TimerDelegate = FTimerDelegate::CreateUObject(
this, &URRTimerManager::SetTimerImple);
459 GetWorld()->GetTimerManager().SetTimer(
TimerHandle, TimerDelegate,
Rate,
false);
485 if (Delegate.IsBound())
489 Delegate.ExecuteIfBound();
497 UE_LOG_WITH_INFO(LogTemp, Error, TEXT(
"[%s] Delegate is not bound"), *LogInfo);
503 float now = UGameplayStatics::GetTimeSeconds(GetWorld());
529 TEXT(
"[URRTimerManager::SetTimerImple][%s] Delegate function call take longer than Rate or StepSize is not "
531 "small enough to meet target Rate=%f, "
539 FApp::GetFixedDeltaTime());
543 wt = FApp::GetFixedDeltaTime() * 0.5;
551 GetWorld()->GetTimerManager().SetTimer(
TimerHandle, TimerDelegate, wt,
false);
572 static builtin_interfaces__msg__Time FloatToROSStamp(
const float InTimeSec)
576 builtin_interfaces__msg__Time stamp;
578 stamp.sec =
static_cast<int32
>(InTimeSec);
580 stamp.nanosec = uint32((InTimeSec - stamp.sec) * 1e+09f);
588 static builtin_interfaces__msg__Time GetCurrentROS2Time(
const UObject* InContextObject)
592 return FloatToROSStamp(UGameplayStatics::GetTimeSeconds(InContextObject->GetWorld()));
598 static float ROSStampToFloat(
const builtin_interfaces__msg__Time& InTimeStamp)
602 return InTimeStamp.sec + InTimeStamp.nanosec * 1e-09f;
608 static void GenerateRandomUUID16(TArray<uint, TFixedAllocator<16>>& OutUUID)
614 for (int8 i = 0; i < 16; i++)
618 OutUUID.Add(std::random_device{}());
626 static int32 GetStringRequiredCapacity(
const FString& InStr)
630 FTCHARToUTF8 strUtf8(*InStr);
632 return (strUtf8.Length() + 1) +
sizeof(size_t) +
sizeof(
size_t);
638 static int32 GetStringArrayRequiredCapacity(
const TArray<FString>& InStrList)
642 int32 totalCapacity = 0;
644 for (
const auto& str : InStrList)
648 totalCapacity += GetStringRequiredCapacity(str);
652 return totalCapacity;
658 static void StringUEToStdMsg(
const FString& InStr, std_msgs__msg__String& OutStdMsg)
662 const unsigned int msgStringCapacity = InStr.Len() + 1;
664 if (OutStdMsg.data.data !=
nullptr)
668 free(OutStdMsg.data.data);
672 OutStdMsg.data.data = (
char*)malloc(msgStringCapacity);
674 OutStdMsg.data.capacity = msgStringCapacity;
676 snprintf(OutStdMsg.data.data, OutStdMsg.data.capacity,
"%s", TCHAR_TO_UTF8(*InStr));
678 OutStdMsg.data.size = strlen(OutStdMsg.data.data);
704 template<
typename TSequence>
710 if (InSequence.data !=
nullptr)
714 free(InSequence.data);
716 InSequence.data =
nullptr;
720 InSequence.data = (decltype(InSequence.data))malloc(size *
sizeof(decltype(*(InSequence.data))));
722 InSequence.size = size;
724 InSequence.capacity = size;
748 template<
typename TSequence,
typename T>
754 for (
auto i = 0; i < size; ++i)
758 if constexpr (TIsArithmetic<T>::Value)
762 OutSequence[i] = InArray[i];
770 InArray[i].SetROS2(OutSequence[i]);
798 template<
typename TSequence,
typename T>
804 OutArray.SetNum(size);
806 for (
auto i = 0; i < size; ++i)
810 if constexpr (TIsArithmetic<T>::Value)
814 OutArray[i] = InSequence[i];
822 OutArray[i].SetFromROS2(InSequence[i]);
860 outStr.AppendChars(InStr.data, InStr.size);
894 for (
size_t i = 0; i < size; ++i)
898 OutStrArray.Emplace(StringROSToUE<T>(InStrSequence[i]));
922 static bool StringUEToROS(
const FString& InStr, rosidl_runtime_c__String& OutStr)
930 rosidl_runtime_c__String__init(&OutStr);
934 bool succeeded = rosidl_runtime_c__String__assign(&OutStr, TCHAR_TO_ANSI(*InStr));
940 UE_LOG_WITH_INFO(LogTemp, Error, TEXT(
"failed to assign string : %s"), *InStr);
978 rosidl_runtime_c__U16String__init(&OutStr);
982 bool succeeded = rosidl_runtime_c__U16String__assignn_from_char(&OutStr, TCHAR_TO_ANSI(*InStr), InStr.Len());
988 UE_LOG_WITH_INFO(LogTemp, Error, TEXT(
"failed to assign u16string : %s"), *InStr);
1018 rosidl_runtime_c__String* OutStrSequence,
1024 for (
auto i = 0; i < size; ++i)
1052 rosidl_runtime_c__U16String* OutStrSequence,
1058 for (
auto i = 0; i < size; ++i)
1086 template<
typename TVector>
1092 return FVector(InROSVector.x, InROSVector.y, InROSVector.z);
1114 template<
typename TVector>
1120 OutUEVector.Empty();
1122 for (
auto i = 0; i < size; ++i)
1126 OutUEVector.Emplace(InROSVector[i].x, InROSVector[i].y, InROSVector[i].z);
1148 template<
typename TVector>
1154 TVector OutROSVector;
1156 OutROSVector.x = InUEVector.X;
1158 OutROSVector.y = InUEVector.Y;
1160 OutROSVector.z = InUEVector.Z;
1164 return OutROSVector;
1186 template<
typename TVector>
1192 for (
auto i = 0; i < size; ++i)
1196 OutROSVector[i].x = InUEVector[i].X;
1198 OutROSVector[i].y = InUEVector[i].Y;
1200 OutROSVector[i].z = InUEVector[i].Z;
1222 static FQuat
QuatROSToUE(
const geometry_msgs__msg__Quaternion& InROSQuat)
1226 return FQuat(InROSQuat.x, InROSQuat.y, InROSQuat.z, InROSQuat.w);
1252 for (
auto i = 0; i < size; ++i)
1256 OutUEQuat.Emplace(InROSQuat[i].x, InROSQuat[i].y, InROSQuat[i].z, InROSQuat[i].w);
1276 static geometry_msgs__msg__Quaternion
QuatUEToROS(
const FQuat& InUEQuat)
1280 geometry_msgs__msg__Quaternion OutROSQuat;
1282 OutROSQuat.x = InUEQuat.X;
1284 OutROSQuat.y = InUEQuat.Y;
1286 OutROSQuat.z = InUEQuat.Z;
1288 OutROSQuat.w = InUEQuat.W;
1316 for (
auto i = 0; i < size; ++i)
1320 OutROSQuat[i].x = InUEQuat[i].X;
1322 OutROSQuat[i].y = InUEQuat[i].Y;
1324 OutROSQuat[i].x = InUEQuat[i].Z;
1326 OutROSQuat[i].w = InUEQuat[i].W;
1352 return FTransform(
QuatROSToUE(InROSTF.rotation), VectorROSToUE<geometry_msgs__msg__Vector3>(InROSTF.translation));
1374 TArray<FTransform>& OutUETF,
1382 for (
auto i = 0; i < size; ++i)
1386 OutUETF.Emplace(
QuatROSToUE(InROSTF[i].rotation), VectorROSToUE<geometry_msgs__msg__Vector3>(InROSTF[i].translation));
1410 geometry_msgs__msg__Transform OutROSTF;
1412 OutROSTF.translation = VectorUEToROS<geometry_msgs__msg__Vector3>(InUETF.GetTranslation());
1414 OutROSTF.rotation =
QuatUEToROS(InUETF.GetRotation());
1440 geometry_msgs__msg__Transform* OutROSTF,
1446 for (
auto i = 0; i < size; ++i)
1450 OutROSTF[i].translation = VectorUEToROS<geometry_msgs__msg__Vector3>(InUETF[i].GetTranslation());
1452 OutROSTF[i].rotation =
QuatUEToROS(InUETF[i].GetRotation());