CARLA
InertialMeasurementUnit.cpp
Go to the documentation of this file.
1 // Copyright (c) 2019 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 
7 #include "Carla.h"
8 
13 
15 #include "carla/geom/Math.h"
16 #include "carla/ros2/ROS2.h"
18 
19 #include <limits>
20 
21 // Based on OpenDRIVE's lon and lat
23  FVector(0.0f, -1.0f, 0.0f);
24 
26  const FObjectInitializer &ObjectInitializer)
27  : Super(ObjectInitializer)
28 {
29  PrimaryActorTick.bCanEverTick = true;
30  PrimaryActorTick.TickGroup = TG_PostPhysics;
31  RandomEngine = CreateDefaultSubobject<URandomEngine>(TEXT("RandomEngine"));
32  PrevLocation = { FVector::ZeroVector, FVector::ZeroVector };
33  // Initialized to something hight to minimize the artifacts
34  // when the initial values are unknown
35  PrevDeltaTime = std::numeric_limits<float>::max();
36 }
37 
39 {
41 }
42 
43 void AInertialMeasurementUnit::Set(const FActorDescription &ActorDescription)
44 {
45  Super::Set(ActorDescription);
46  UActorBlueprintFunctionLibrary::SetIMU(ActorDescription, this);
47 }
48 
50 {
51  Super::SetOwner(Owner);
52 }
53 
54 // Returns the angular velocity of Actor, expressed in the frame of Actor
56  AActor &Actor)
57 {
58  const auto RootComponent = Cast<UPrimitiveComponent>(Actor.GetRootComponent());
59 
60  FVector AngularVelocity;
61 
62  if (RootComponent != nullptr) {
63  const FQuat ActorGlobalRotation = RootComponent->GetComponentTransform().GetRotation();
64  const FVector GlobalAngularVelocity = RootComponent->GetPhysicsAngularVelocityInRadians();
65  AngularVelocity = ActorGlobalRotation.UnrotateVector(GlobalAngularVelocity);
66  } else {
67  AngularVelocity = FVector::ZeroVector;
68  }
69 
70  return AngularVelocity;
71 }
72 
74  const FVector &Accelerometer)
75 {
76  // Normal (or Gaussian or Gauss) distribution will be used as noise function.
77  // A mean of 0.0 is used as a first parameter, the standard deviation is
78  // determined by the client
79  constexpr float Mean = 0.0f;
80  return carla::geom::Vector3D {
81  Accelerometer.X + RandomEngine->GetNormalDistribution(Mean, StdDevAccel.X),
82  Accelerometer.Y + RandomEngine->GetNormalDistribution(Mean, StdDevAccel.Y),
83  Accelerometer.Z + RandomEngine->GetNormalDistribution(Mean, StdDevAccel.Z)
84  };
85 }
86 
88  const FVector &Gyroscope)
89 {
90  // Normal (or Gaussian or Gauss) distribution and a bias will be used as
91  // noise function.
92  // A mean of 0.0 is used as a first parameter.The standard deviation and the
93  // bias are determined by the client
94  constexpr float Mean = 0.0f;
95  return carla::geom::Vector3D {
96  Gyroscope.X + BiasGyro.X + RandomEngine->GetNormalDistribution(Mean, StdDevGyro.X),
97  Gyroscope.Y + BiasGyro.Y + RandomEngine->GetNormalDistribution(Mean, StdDevGyro.Y),
98  Gyroscope.Z + BiasGyro.Z + RandomEngine->GetNormalDistribution(Mean, StdDevGyro.Z)
99  };
100 }
101 
103  const float DeltaTime)
104 {
105  // Used to convert from UE4's cm to meters
106  constexpr float TO_METERS = 1e-2;
107  // Earth's gravitational acceleration is approximately 9.81 m/s^2
108  constexpr float GRAVITY = 9.81f;
109 
110  // 2nd derivative of the polynomic (quadratic) interpolation
111  // using the point in current time and two previous steps:
112  // d2[i] = -2.0*(y1/(h1*h2)-y2/((h2+h1)*h2)-y0/(h1*(h2+h1)))
113  const FVector CurrentLocation = GetActorLocation();
114 
115  const FVector Y2 = PrevLocation[0];
116  const FVector Y1 = PrevLocation[1];
117  const FVector Y0 = CurrentLocation;
118  const float H1 = DeltaTime;
119  const float H2 = PrevDeltaTime;
120 
121  const float H1AndH2 = H2 + H1;
122  const FVector A = Y1 / ( H1 * H2 );
123  const FVector B = Y2 / ( H2 * (H1AndH2) );
124  const FVector C = Y0 / ( H1 * (H1AndH2) );
125  FVector FVectorAccelerometer = TO_METERS * -2.0f * ( A - B - C );
126 
127  // Update the previous locations
128  PrevLocation[0] = PrevLocation[1];
129  PrevLocation[1] = CurrentLocation;
130  PrevDeltaTime = DeltaTime;
131 
132  // Add gravitational acceleration
133  FVectorAccelerometer.Z += GRAVITY;
134 
135  FQuat ImuRotation =
136  GetRootComponent()->GetComponentTransform().GetRotation();
137  FVectorAccelerometer = ImuRotation.UnrotateVector(FVectorAccelerometer);
138 
139  // Cast from FVector to our Vector3D to correctly send the data in m/s^2
140  // and apply the desired noise function, in this case a normal distribution
141  const carla::geom::Vector3D Accelerometer =
142  ComputeAccelerometerNoise(FVectorAccelerometer);
143 
144  return Accelerometer;
145 }
146 
148 {
149  check(GetOwner() != nullptr);
150  const FVector AngularVelocity =
152 
153  const FQuat SensorLocalRotation =
154  RootComponent->GetRelativeTransform().GetRotation();
155 
156  const FVector FVectorGyroscope =
157  SensorLocalRotation.RotateVector(AngularVelocity);
158 
159  // Cast from FVector to our Vector3D to correctly send the data in rad/s
160  // and apply the desired noise function, in this case a normal distribution
161  const carla::geom::Vector3D Gyroscope =
162  ComputeGyroscopeNoise(FVectorGyroscope);
163 
164  return Gyroscope;
165 }
166 
168 {
169  // Magnetometer: orientation with respect to the North in rad
170  const FVector ForwVect = GetActorForwardVector().GetSafeNormal2D();
171  const float DotProd = FVector::DotProduct(CarlaNorthVector, ForwVect);
172 
173  // We check if the dot product is higher than 1.0 due to numerical error
174  if (DotProd >= 1.00f)
175  return 0.0f;
176 
177  const float Compass = std::acos(DotProd);
178  // Keep the angle between [0, 2pi)
179  if (FVector::CrossProduct(CarlaNorthVector, ForwVect).Z < 0.0f)
180  return carla::geom::Math::Pi2<float>() - Compass;
181 
182  return Compass;
183 }
184 
185 void AInertialMeasurementUnit::PostPhysTick(UWorld *World, ELevelTick TickType, float DeltaTime)
186 {
187  carla::geom::Vector3D Accelerometer = ComputeAccelerometer(DeltaTime);
189  float Compass = ComputeCompass();
190 
191  auto Stream = GetDataStream(*this);
192 
193  // ROS2
194  #if defined(WITH_ROS2)
195  auto ROS2 = carla::ros2::ROS2::GetInstance();
196  if (ROS2->IsEnabled())
197  {
198  TRACE_CPUPROFILER_EVENT_SCOPE_STR("ROS2 Send");
200  AActor* ParentActor = GetAttachParentActor();
201  if (ParentActor)
202  {
203  FTransform LocalTransformRelativeToParent = GetActorTransform().GetRelativeTransform(ParentActor->GetActorTransform());
204  ROS2->ProcessDataFromIMU(Stream.GetSensorType(), StreamId, LocalTransformRelativeToParent, Accelerometer, Gyroscope, Compass, this);
205  }
206  else
207  {
208  ROS2->ProcessDataFromIMU(Stream.GetSensorType(), StreamId, Stream.GetSensorTransform(), Accelerometer, Gyroscope, Compass, this);
209  }
210  }
211  #endif
212 
213  {
214  TRACE_CPUPROFILER_EVENT_SCOPE(AInertialMeasurementUnit::PostPhysTick);
215  Stream.SerializeAndSend(*this, Accelerometer, Gyroscope, Compass);
216  }
217 }
218 
220 {
221  StdDevAccel = Vec;
222 }
223 
225 {
226  StdDevGyro = Vec;
227 }
228 
230 {
231  BiasGyro = Vec;
232 }
233 
235 {
236  return StdDevAccel;
237 }
238 
240 {
241  return StdDevGyro;
242 }
243 
245 {
246  return BiasGyro;
247 }
248 
250 {
251  Super::BeginPlay();
252 }
static FActorDefinition GetSensorDefinition()
auto GetToken() const
Return the token that allows subscribing to this sensor&#39;s stream.
float ComputeCompass()
Magnetometer: orientation with respect to the North in rad.
FVector StdDevGyro
Standard deviation for gyroscope settings.
const carla::geom::Vector3D ComputeGyroscopeNoise(const FVector &Gyroscope)
void SetOwner(AActor *Owner) override
A definition of a Carla Actor with all the variation and attributes.
const FVector & GetGyroscopeBias() const
const FVector & GetAccelerationStandardDeviation() const
static void SetIMU(const FActorDescription &Description, AInertialMeasurementUnit *IMU)
std::array< FVector, 2 > PrevLocation
Used to compute the acceleration.
carla::geom::Vector3D ComputeGyroscope()
Gyroscope: measures angular velocity in rad/sec.
FVector BiasGyro
Bias for gyroscope settings.
carla::SharedPtr< cc::Actor > Actor
virtual void PostPhysTick(UWorld *World, ELevelTick TickType, float DeltaTime) override
void Set(const FActorDescription &ActorDescription) override
A description of a Carla Actor with all its variation.
float PrevDeltaTime
Used to compute the acceleration.
void SetGyroscopeBias(const FVector &Vec)
const auto & get_stream_id() const
Definition: detail/Token.h:116
const FVector & GetGyroscopeStandardDeviation() const
const carla::geom::Vector3D ComputeAccelerometerNoise(const FVector &Accelerometer)
void SetGyroscopeStandardDeviation(const FVector &Vec)
FAsyncDataStream GetDataStream(const SensorT &Self)
Return the FDataStream associated with this sensor.
static const FVector CarlaNorthVector
Based on OpenDRIVE&#39;s lon and lat, North is in (0.0f, -1.0f, 0.0f)
static std::shared_ptr< ROS2 > GetInstance()
Definition: ROS2.h:51
void SetAccelerationStandardDeviation(const FVector &Vec)
float GetNormalDistribution(float Mean, float StandardDeviation)
Definition: RandomEngine.h:110
uint64_t GetSensorType()
Definition: DataStream.h:58
FVector StdDevAccel
Standard deviation for acceleration settings.
static FVector FIMU_GetActorAngularVelocityInRadians(AActor &Actor)
carla::streaming::detail::token_type token_type
carla::geom::Vector3D ComputeAccelerometer(const float DeltaTime)
Accelerometer: measures linear acceleration in m/s^2.
AInertialMeasurementUnit(const FObjectInitializer &ObjectInitializer)
URandomEngine * RandomEngine
Random Engine used to provide noise for sensor output.