CARLA
Loading...
Searching...
No Matches
sensorSync.h
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB).
2// This work is licensed under the terms of the MIT license.
3// For a copy, see <https://opensource.org/licenses/MIT>.
4
5#pragma once
6
8
9#include <array>
10#include <cstdint>
11#include <istream>
12#include <optional>
13#include <ostream>
14#include <random>
15#include <sstream>
16#include <string>
17#include <vector>
18
19namespace carla {
20namespace multigpu {
21
22 /// One record of frame data packet 26: a sensor of the primary that ticks
23 /// in this frame, and the delta of that tick.
24 struct SensorTick {
25 uint32_t actor_id = 0u;
26 float delta_seconds = 0.0f;
27 };
28
29 /// Frame data packet 26: every sensor of the primary that ticks in this
30 /// frame. A secondary's mirrors tick on exactly these frames, with these
31 /// deltas, whatever their own tick interval says, so their sensor_tick
32 /// phase is the primary's even if they were created later. Written on every
33 /// frame, even when empty.
34 struct SensorTicks {
35
36 static constexpr uint8_t kPacketId = 26u;
37
38 static constexpr uint16_t kRecordSizeV1 = 8u;
39
40 std::vector<SensorTick> ticks;
41
42 void Write(std::ostream &out) const {
43 const uint32_t count = static_cast<uint32_t>(ticks.size());
44 WriteFrameDataHeader(out, kPacketId, sizeof(uint32_t) + sizeof(uint16_t) + count * kRecordSizeV1);
46 for (const SensorTick &tick : ticks) {
47 detail::WritePod(out, tick.actor_id);
48 detail::WritePod(out, tick.delta_seconds);
49 }
50 }
51
52 bool Read(std::istream &in, uint32_t size) {
53 ticks.clear();
54 BoundedReader reader(in, size);
55 uint32_t count = 0u;
56 uint16_t record_size = 0u;
57 if (!reader.ReadFixedListHeader(kRecordSizeV1, count, record_size)) {
58 return false;
59 }
60 ticks.reserve(count);
61 for (uint32_t i = 0u; i < count; ++i) {
62 SensorTick tick;
63 const bool ok = reader.ReadRecord(record_size, [&](BoundedReader &record) {
64 return record.Read(tick.actor_id) && record.Read(tick.delta_seconds);
65 });
66 if (!ok) {
67 return false;
68 }
69 ticks.push_back(tick);
70 }
71 return true;
72 }
73 };
74
75 /// An IMU's history: its two previous locations (world, cm) and the delta
76 /// between them; its accelerometer is a second difference over them.
77 struct ImuHistory {
78 std::array<double, 3> older_location = {0.0, 0.0, 0.0};
79 std::array<double, 3> last_location = {0.0, 0.0, 0.0};
80 float last_delta_seconds = 0.0f;
81 };
82
83 /// One record of frame data packet 27: the runtime state a sensor of the
84 /// primary starts this frame's tick from. A mirror created at another frame
85 /// starts from its own defaults; with this it computes exactly what the
86 /// primary's sensor would.
87 struct SensorState {
88 uint32_t actor_id = 0u;
89 /// URandomEngine (noise, lidar drop-off, radar ray directions).
90 std::optional<uint32_t> random_engine;
91 /// Ray-cast lidars: where this tick's sweep starts (radians).
92 std::optional<float> lidar_horizontal_angle;
93 std::optional<ImuHistory> imu_history;
94 /// Radar: its previous location (world, cm), for its own velocity.
95 std::optional<std::array<double, 3>> radar_previous_location;
96 /// IMU: its rotation relative to its parent (x, y, z, w), which turns the
97 /// parent's angular velocity into the gyroscope's. A mirror is attached
98 /// rigidly, so a spring arm's rotation would differ.
99 std::optional<std::array<double, 4>> imu_local_rotation;
100
105 };
106
107 /// Frame data packet 27, for the sensors of packet 26 that carry state.
109
110 static constexpr uint8_t kPacketId = 27u;
111
112 /// Field kinds; a reader skips the kinds it does not know.
120
121 std::vector<SensorState> states;
122
123 void Write(std::ostream &out) const {
124 std::ostringstream payload;
125 detail::WritePod(payload, static_cast<uint32_t>(states.size()));
126 for (const SensorState &state : states) {
127 std::ostringstream record;
128 detail::WritePod(record, state.actor_id);
129 if (state.random_engine) {
130 WriteField(record, kRandomEngine, Bytes(*state.random_engine));
131 }
132 if (state.lidar_horizontal_angle) {
133 WriteField(record, kLidarHorizontalAngle, Bytes(*state.lidar_horizontal_angle));
134 }
135 if (state.imu_history) {
136 std::ostringstream value;
137 WriteVector(value, state.imu_history->older_location);
138 WriteVector(value, state.imu_history->last_location);
139 detail::WritePod(value, state.imu_history->last_delta_seconds);
140 WriteField(record, kImuHistory, value.str());
141 }
142 if (state.radar_previous_location) {
143 std::ostringstream value;
144 WriteVector(value, *state.radar_previous_location);
145 WriteField(record, kRadarPreviousLocation, value.str());
146 }
147 if (state.imu_local_rotation) {
148 std::ostringstream value;
149 for (double axis : *state.imu_local_rotation) {
150 detail::WritePod(value, axis);
151 }
152 WriteField(record, kImuLocalRotation, value.str());
153 }
154 WriteSizedBytes(payload, record.str());
155 }
156 WriteFrameDataPacket(out, kPacketId, payload.str());
157 }
158
159 bool Read(std::istream &in, uint32_t size) {
160 states.clear();
161 BoundedReader reader(in, size);
162 uint32_t count = 0u;
163 if (!reader.ReadVariableListCount(count)) {
164 return false;
165 }
166 for (uint32_t i = 0u; i < count; ++i) {
167 SensorState state;
168 const bool ok = reader.ReadSizedRecord([&](BoundedReader &record) {
169 return record.Read(state.actor_id) && record.ReadFields([&](uint8_t kind, BoundedReader &value) {
170 switch (kind) {
171 case kRandomEngine: {
172 uint32_t engine = 0u;
173 if (!value.Read(engine)) {
174 return false;
175 }
176 state.random_engine = engine;
177 return true;
178 }
179 case kLidarHorizontalAngle: {
180 float angle = 0.0f;
181 if (!value.Read(angle)) {
182 return false;
183 }
184 state.lidar_horizontal_angle = angle;
185 return true;
186 }
187 case kImuHistory: {
188 ImuHistory history;
189 if (!ReadVector(value, history.older_location) ||
190 !ReadVector(value, history.last_location) ||
191 !value.Read(history.last_delta_seconds)) {
192 return false;
193 }
194 state.imu_history = history;
195 return true;
196 }
197 case kRadarPreviousLocation: {
198 std::array<double, 3> location;
199 if (!ReadVector(value, location)) {
200 return false;
201 }
202 state.radar_previous_location = location;
203 return true;
204 }
205 case kImuLocalRotation: {
206 std::array<double, 4> rotation;
207 for (double &axis : rotation) {
208 if (!value.Read(axis)) {
209 return false;
210 }
211 }
212 state.imu_local_rotation = rotation;
213 return true;
214 }
215 default:
216 return true; // a kind of a newer build: skipped
217 }
218 });
219 });
220 if (!ok) {
221 return false;
222 }
223 states.push_back(std::move(state));
224 }
225 return true;
226 }
227
228 private:
229
230 template <typename T>
231 static std::string Bytes(const T &value) {
232 std::ostringstream out;
233 detail::WritePod(out, value);
234 return out.str();
235 }
236
237 static void WriteVector(std::ostream &out, const std::array<double, 3> &vector) {
238 for (double value : vector) {
239 detail::WritePod(out, value);
240 }
241 }
242
243 static bool ReadVector(BoundedReader &reader, std::array<double, 3> &vector) {
244 for (double &value : vector) {
245 if (!reader.Read(value)) {
246 return false;
247 }
248 }
249 return true;
250 }
251 };
252
253 /// The state of a minstd_rand: the value its next draw is computed from.
254 inline uint32_t GetEngineState(const std::minstd_rand &engine) {
255 std::minstd_rand copy = engine;
256 // copy() returns 48271 * x mod (2^31 - 1); 1899818559 is 48271's
257 // inverse modulo 2^31 - 1, so this recovers x.
258 const uint64_t next = copy();
259 return static_cast<uint32_t>((next * uint64_t{1899818559u}) % uint64_t{2147483647u});
260 }
261
262 /// Makes @a engine continue from @a state, as GetEngineState returned it.
263 /// False for a value no minstd_rand can hold.
264 inline bool SetEngineState(std::minstd_rand &engine, uint32_t state) {
265 if ((state == 0u) || (state >= std::minstd_rand::modulus)) {
266 return false;
267 }
268 engine.seed(state);
269 return true;
270 }
271
272} // namespace multigpu
273} // namespace carla
Reads the fields of one packet (or one record inside it) without ever consuming more than its declare...
bool ReadFixedListHeader(uint16_t min_record_size, uint32_t &count, uint16_t &record_size)
Header of a list of fixed-size records, checked against the bytes left.
bool ReadRecord(uint32_t bytes, F &&read)
Runs read(record) on the next bytes as a reader of their own, then skips what it left unread (a recor...
bool ReadSizedRecord(F &&read)
Reads one [u32 record_size][record] entry of a variable-size list.
bool ReadVariableListCount(uint32_t &count)
Count of a list of variable-size records, checked against the bytes left.
bool ReadFields(F &&read)
Reads TLV fields until the reader is exhausted.
void WritePod(std::ostream &out, const T &value)
uint32_t GetEngineState(const std::minstd_rand &engine)
The state of a minstd_rand: the value its next draw is computed from.
Definition sensorSync.h:254
void WriteFixedListHeader(std::ostream &out, uint32_t count, uint16_t record_size)
Header of a list of fixed-size records.
bool SetEngineState(std::minstd_rand &engine, uint32_t state)
Makes engine continue from state, as GetEngineState returned it.
Definition sensorSync.h:264
void WriteField(std::ostream &out, uint8_t kind, const std::string &value)
void WriteFrameDataHeader(std::ostream &out, uint8_t id, uint32_t payload_size)
void WriteSizedBytes(std::ostream &out, const std::string &bytes)
One [u32 size][bytes] entry: a variable-size record or, after a kind byte, a TLV value.
void WriteFrameDataPacket(std::ostream &out, uint8_t id, const std::string &payload)
Writes a packet whose payload was built beforehand.
This file contains definitions of common data structures used in traffic manager.
An IMU's history: its two previous locations (world, cm) and the delta between them; its acceleromete...
Definition sensorSync.h:77
std::array< double, 3 > last_location
Definition sensorSync.h:79
std::array< double, 3 > older_location
Definition sensorSync.h:78
One record of frame data packet 27: the runtime state a sensor of the primary starts this frame's tic...
Definition sensorSync.h:87
std::optional< ImuHistory > imu_history
Definition sensorSync.h:93
std::optional< float > lidar_horizontal_angle
Ray-cast lidars: where this tick's sweep starts (radians).
Definition sensorSync.h:92
std::optional< std::array< double, 4 > > imu_local_rotation
IMU: its rotation relative to its parent (x, y, z, w), which turns the parent's angular velocity into...
Definition sensorSync.h:99
std::optional< std::array< double, 3 > > radar_previous_location
Radar: its previous location (world, cm), for its own velocity.
Definition sensorSync.h:95
std::optional< uint32_t > random_engine
URandomEngine (noise, lidar drop-off, radar ray directions).
Definition sensorSync.h:90
Frame data packet 27, for the sensors of packet 26 that carry state.
Definition sensorSync.h:108
std::vector< SensorState > states
Definition sensorSync.h:121
void Write(std::ostream &out) const
Definition sensorSync.h:123
static constexpr uint8_t kPacketId
Definition sensorSync.h:110
bool Read(std::istream &in, uint32_t size)
Definition sensorSync.h:159
static std::string Bytes(const T &value)
Definition sensorSync.h:231
Field
Field kinds; a reader skips the kinds it does not know.
Definition sensorSync.h:113
static void WriteVector(std::ostream &out, const std::array< double, 3 > &vector)
Definition sensorSync.h:237
static bool ReadVector(BoundedReader &reader, std::array< double, 3 > &vector)
Definition sensorSync.h:243
One record of frame data packet 26: a sensor of the primary that ticks in this frame,...
Definition sensorSync.h:24
Frame data packet 26: every sensor of the primary that ticks in this frame.
Definition sensorSync.h:34
static constexpr uint8_t kPacketId
Definition sensorSync.h:36
std::vector< SensorTick > ticks
Definition sensorSync.h:40
static constexpr uint16_t kRecordSizeV1
Definition sensorSync.h:38
void Write(std::ostream &out) const
Definition sensorSync.h:42
bool Read(std::istream &in, uint32_t size)
Definition sensorSync.h:52