CARLA
Loading...
Searching...
No Matches
VehicleStatusSensor.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8
9#include "Carla.h"
16
17#include <util/ue-header-guard-begin.h>
18#include "Engine/World.h"
19#include "TimerManager.h"
20#include <util/ue-header-guard-end.h>
21
23#include "carla/ros2/ROS2.h"
25
26AVehicleStatusSensor::AVehicleStatusSensor(const FObjectInitializer &ObjectInitializer)
27 : Super(ObjectInitializer)
28{
29 PrimaryActorTick.bCanEverTick = true;
30 PrimaryActorTick.TickGroup = TG_PostPhysics; // read ground-truth after physics update
31
33 PrimaryActorTick.TickInterval = 1.0f / TargetRateHz;
34}
35
40
41void AVehicleStatusSensor::Set(const FActorDescription &ActorDescription)
42{
43 Super::Set(ActorDescription);
44}
45
47{
48 Super::BeginPlay();
49 UE_LOG(LogCarla, Log, TEXT("VehicleStatusSensor spawned."));
50 GetWorldTimerManager().SetTimer(CheckParentTimerHandle, this, &AVehicleStatusSensor::CheckForParentVehicle, 1.0f, true);
51}
52
53void AVehicleStatusSensor::PostPhysTick(UWorld *World, ELevelTick TickType, float DeltaSeconds)
54{
55 Super::PostPhysTick(World, TickType, DeltaSeconds);
56 CollectAndStream(DeltaSeconds);
57}
58
60{
62 {
63 UE_LOG(LogCarla, Log, TEXT("VehicleStatusSensor attached to a vehicle: %s"), *OwningVehicle->GetName());
64 GetWorldTimerManager().ClearTimer(CheckParentTimerHandle);
65 }
66}
67
68TObjectPtr<ACarlaWheeledVehicle> AVehicleStatusSensor::FindAttachmentParentVehicle() const
69{
70 for (AActor* Parent = GetAttachParentActor(); Parent; Parent = Parent->GetAttachParentActor())
71 {
72 if (ACarlaWheeledVehicle* Vehicle = Cast<ACarlaWheeledVehicle>(Parent))
73 {
74 return Vehicle;
75 }
76 }
77 return nullptr;
78}
79
80void AVehicleStatusSensor::CollectAndStream(float /*DeltaSeconds*/)
81{
82 const UCarlaEpisode *CurrentEpisode = UCarlaStatics::GetCurrentEpisode(GetWorld());
83 if (!OwningVehicle.IsValid() && (CurrentEpisode != nullptr) && !CurrentEpisode->bIsPrimaryServer)
84 {
85 // A Multi-GPU mirror is attached in the frame it is spawned, and streams
86 // from the primary sensor's first tick, not the timer's.
88 }
89 if (!OwningVehicle.IsValid())
90 {
91 return;
92 }
93
95 if (!IsValid(Vehicle))
96 {
97 return;
98 }
99
100 // Update cached velocity info
102
103 // Get Max Steering
104 const auto MaxSteerAngleInRadians = FMath::DegreesToRadians(Vehicle->GetMaximumSteerAngle());
105
106 // Control flags (b0 = reverse, b1 = manual gear shift)
107 const auto& Control = Vehicle->GetVehicleControl();
108 const auto Flags = (Control.bReverse ? 0x01 : 0) | (Control.bManualGearShift ? 0x02 : 0);
109
110 // Turn mask (b0 = left blinker, b1 = right blinker, b2 = hazards)
111 const auto& Lights = Vehicle->GetVehicleLightState();
112 const bool bHazard = Lights.LeftBlinker && Lights.RightBlinker;
113 const auto TurnMask = (Lights.LeftBlinker ? 0x01 : 0) | (Lights.RightBlinker ? 0x02 : 0) | (bHazard ? 0x04 : 0);
114
115 const FVehicleStatusData Msg
116 {
117 static_cast<double>(GetWorld()->GetTimeSeconds()),
118 static_cast<float>(VelocityInfo.GetSpeed()),
119 static_cast<float>(VelocityInfo.Velocity.X),
120 static_cast<float>(VelocityInfo.Velocity.Y),
121 static_cast<float>(VelocityInfo.Velocity.Z),
122 static_cast<float>(VelocityInfo.AngularVelocity.X),
123 static_cast<float>(VelocityInfo.AngularVelocity.Y),
124 static_cast<float>(VelocityInfo.AngularVelocity.Z),
125 static_cast<float>(Vehicle->GetActorRotation().Pitch),
126 static_cast<float>(Vehicle->GetActorRotation().Yaw),
127 static_cast<float>(Vehicle->GetActorRotation().Roll),
128 static_cast<float>(Vehicle->GetVehicleControl().Steer * MaxSteerAngleInRadians),
129 static_cast<int32_t>(Vehicle->GetVehicleCurrentGear()),
130 static_cast<uint8_t>(TurnMask),
131 static_cast<uint8_t>(Flags),
132 };
133
134 auto DataStream = GetDataStream(*this);
135
136 // ROS2 forwarding
137#if defined(WITH_ROS2)
138 if (auto ROS2 = carla::ros2::ROS2::GetInstance(); ROS2->IsEnabled())
139 {
140 TRACE_CPUPROFILER_EVENT_SCOPE_STR("ROS2 Send");
142 ROS2->ProcessDataFromStatusSensor(
143 DataStream.GetSensorType(),
144 StreamId,
145 GetActorTransform(),
146 Msg,
147 Vehicle,
148 this);
149 }
150#endif
151
152 // UE client streaming (field-wise VehicleStatusSerializer overload)
153 {
154 TRACE_CPUPROFILER_EVENT_SCOPE_STR("AVehicleStatusSensor Stream Send");
155 DataStream.SerializeAndSend(
156 *this,
157 Msg.timestamp,
158 Msg.speed_mps,
159 Msg.vel_x_mps, Msg.vel_y_mps, Msg.vel_z_mps,
160 Msg.angVel_x_mps, Msg.angVel_y_mps, Msg.angVel_z_mps,
161 Msg.rot_pitch, Msg.rot_yaw, Msg.rot_roll,
162 Msg.steer,
163 Msg.gear,
164 Msg.turn_mask,
165 Msg.control_flags);
166 }
167}
168
170{
171 if (!VehicleActor)
172 {
173 return;
174 }
175
176 // World linear velocity (cm/s)
177 const FVector WorldVel_cmps = VehicleActor->GetVelocity();
178
179 // Convert to m/s, then rotate into local space
180 const FQuat InvRot = VehicleActor->GetActorTransform().GetRotation().Inverse();
181 VelocityInfo.Velocity = InvRot.RotateVector(CmpsToMps(WorldVel_cmps));
182
183 // Physics angular velocity (rad/s, world space); a Multi-GPU mirror, which
184 // never simulates, has the primary's, when the primary's body simulates.
185 FVector WorldAngVel = FVector::ZeroVector;
186 if (const auto* MirroredVehicle = Cast<ACarlaWheeledVehicle>(VehicleActor);
187 (MirroredVehicle != nullptr) && MirroredVehicle->HasMirroredMotion())
188 {
189 if (MirroredVehicle->IsMirroredSimulatingPhysics())
190 {
191 WorldAngVel = CarlaGetActorAngularVelocityInRadians(*VehicleActor);
192 }
193 }
194 else if (UPrimitiveComponent* RootPrim = Cast<UPrimitiveComponent>(VehicleActor->GetRootComponent()))
195 {
196 if (RootPrim->IsSimulatingPhysics())
197 {
198 WorldAngVel = RootPrim->GetPhysicsAngularVelocityInRadians();
199 }
200 }
201
202 // Rotate into local space
203 VelocityInfo.AngularVelocity = InvRot.RotateVector(WorldAngVel);
204
205 // Convert angular velocity vector into a Rotator for convenience
207}
FVector CarlaGetActorAngularVelocityInRadians(const AActor &Actor)
Angular velocity of Actor in the world frame, in rad/s: on a Multi-GPU secondary the primary's (a mir...
static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
Base class for CARLA wheeled vehicles.
auto GetToken() const
Return the token that allows subscribing to this sensor's stream.
FAsyncDataStream GetDataStream(SensorType &&Self)
Return the FDataStream associated with this sensor.
virtual void PostPhysTick(UWorld *World, ELevelTick TickType, float DeltaSeconds) override
FTimerHandle CheckParentTimerHandle
TWeakObjectPtr< ACarlaWheeledVehicle > OwningVehicle
TObjectPtr< ACarlaWheeledVehicle > FindAttachmentParentVehicle() const
AVehicleStatusSensor(const FObjectInitializer &ObjectInitializer)
void CollectAndStream(float DeltaSeconds)
void SetVelocityInfoToLocal(const AActor *VehicleActor)
virtual void Set(const FActorDescription &ActorDescription) override
static FORCEINLINE T CmpsToMps(const T &v_cmps)
virtual void BeginPlay() override
static FActorDefinition GetSensorDefinition()
A simulation episode.
static UCarlaEpisode * GetCurrentEpisode(const UObject *WorldContextObject)
static std::shared_ptr< ROS2 > GetInstance()
Definition ROS2.h:61
Serializes a stream endpoint.
A definition of a Carla Actor with all the variation and attributes.
A description of a Carla Actor with all its variation.
float GetSpeed() const
Snapshot of a vehicle's kinematic + control state, streamed each tick by the Autoware VehicleStatusSe...