CARLA
Loading...
Searching...
No Matches
ZenohWireFormat.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
7// Pure keyexpr/wire-format helpers with no zenoh-c dependency; also compiled
8// under CARLA_ROS2_MIDDLEWARE_TESTING so unit tests cover them.
9#if defined(CARLA_ROS2_MIDDLEWARE_ZENOH) || defined(CARLA_ROS2_MIDDLEWARE_TESTING)
10
13
14#include <atomic>
15#include <cstdint>
16#include <string>
17#include <vector>
18
19namespace carla {
20namespace ros2 {
21
22// rmw_zenoh wire-format constants. Values mirror the ones used by
23// zenoh_carla_bridge and by rmw_zenoh peers so all sides speak the same
24// dialect. See https://github.com/ros2/rmw_zenoh/blob/rolling/docs/design.md.
25constexpr const char* kZenohNodeId = "0";
26constexpr const char* kZenohNodeName = "carla_bridge";
27constexpr const char* kZenohEntityKindPub = "MP";
28constexpr const char* kZenohEntityKindSub = "MS";
29constexpr const char* kZenohEntityKindNode = "NN";
30constexpr const char* kZenohDefaultQos = "::,1:,:,:,,";
31
32/// Encode a QosProfile into the rmw_zenoh liveliness-token QoS segment.
33/// Format (rmw_zenoh liveliness_utils qos_to_keyexpr):
34/// "<reliability>:<durability>:<history_kind>,<history_depth>:
35/// <deadline_s>,<deadline_ns>:<lifespan_s>,<lifespan_ns>:
36/// <liveliness_kind>,<liveliness_s>,<liveliness_ns>"
37/// with RMW enum integer values (RELIABLE=1 / BEST_EFFORT=2,
38/// TRANSIENT_LOCAL=1 / VOLATILE=2, KEEP_LAST=1 / KEEP_ALL=2) and empty
39/// fields meaning "system default" (compare kZenohDefaultQos).
40///
41/// NOTE: this only *advertises* the QoS in the graph cache so rmw_zenoh
42/// peers report compatible endpoints. Zenoh delivery semantics are not
43/// differentiated per profile by this backend (in particular there is no
44/// querying-subscriber support, so TRANSIENT_LOCAL late-join latching is
45/// not provided). Needs validation against rmw_zenoh during the smoke
46/// phase.
47inline std::string zenoh_qos_keyexpr(const QosProfile& qos) {
48 const char* rel =
49 qos.reliability == QosProfile::Reliability::Reliable ? "1" : "2";
50 const char* dur =
51 qos.durability == QosProfile::Durability::TransientLocal ? "1" : "2";
52 const char* hist =
53 qos.history == QosProfile::History::KeepLast ? "1" : "2";
54 return std::string(rel) + ":" + dur + ":" + hist + "," +
55 std::to_string(qos.history_depth) + ":,:,:,,";
56}
57
58/// Monotonic per-process counter used to assign a unique entity id (eid) to
59/// each publisher and subscriber declared on the shared Session.
60inline uint64_t zenoh_next_entity_id() {
61 static std::atomic<uint64_t> counter{0};
62 return counter.fetch_add(1, std::memory_order_relaxed);
63}
64
65/// Effective ROS 2 domain id as a string, resolved by the middleware
66/// abstraction layer (--ros-domain-id, else ROS_DOMAIN_ID, else the default
67/// domain 0). Populates the leading segment of every keyexpr so we only match
68/// rmw_zenoh peers on the same domain, mirroring the domain id the
69/// FastDDS/CycloneDDS middlewares pass to their DomainParticipant.
70inline std::string zenoh_ros_domain_id() {
71 return std::to_string(MiddlewareConfig::GetEffectiveDomainId());
72}
73
74/// Strip the "rt/" prefix that ROS2-to-DDS mapping adds to message topics.
75/// rmw_zenoh keyexprs and liveliness tokens use the bare topic name.
76inline std::string zenoh_strip_rt_prefix(const std::string& topic) {
77 return topic.compare(0, 3, "rt/") == 0 ? topic.substr(3) : topic;
78}
79
80/// Replace '/' with '%' so the topic appears as a single segment inside the
81/// slash-separated liveliness keyexpr (e.g. "vehicle/imu" -> "%vehicle%imu").
82inline std::string zenoh_mangle_topic(const std::string& topic) {
83 std::string out;
84 out.reserve(topic.size() + 1u);
85 out.push_back('%');
86 for (char c : topic) out.push_back(c == '/' ? '%' : c);
87 return out;
88}
89
90/// Keyexpr used by declare_publisher / declare_subscriber. Format:
91/// "<domain>/<topic>/<type>/<hash>".
92inline std::string zenoh_make_topic_keyexpr(
93 const std::string& domain,
94 const std::string& topic_no_rt,
95 const char* type_name,
96 [[maybe_unused]] const char* type_hash)
97{
98 return domain + "/" + topic_no_rt + "/" + type_name + "/*";
99}
100
101/// Liveliness keyexpr that registers carla_bridge as a node in rmw_zenoh's
102/// graph cache. Format: "@ros2_lv/<domain>/<zid>/0/0/NN/%/%/carla_bridge".
103inline std::string zenoh_make_node_liveliness_keyexpr(
104 const std::string& domain,
105 const std::string& zid)
106{
107 return std::string("@ros2_lv/") + domain + "/" + zid + "/" + kZenohNodeId +
108 "/" + kZenohNodeId + "/" + kZenohEntityKindNode + "/%/%/" +
109 kZenohNodeName;
110}
111
112/// Liveliness keyexpr that registers one pub/sub endpoint of carla_bridge.
113/// Format:
114/// "@ros2_lv/<domain>/<zid>/0/<eid>/<MP|MS>/%/%/carla_bridge/<mangled>/<type>/<hash>/<qos>".
115inline std::string zenoh_make_topic_liveliness_keyexpr(
116 const std::string& domain,
117 const std::string& zid,
118 uint64_t eid,
119 const char* entity_kind,
120 const std::string& topic_no_rt,
121 const char* type_name,
122 const char* type_hash,
123 const char* qos)
124{
125 return std::string("@ros2_lv/") + domain + "/" + zid + "/" + kZenohNodeId +
126 "/" + std::to_string(eid) + "/" + entity_kind + "/%/%/" +
127 kZenohNodeName + "/" + zenoh_mangle_topic(topic_no_rt) + "/" +
128 type_name + "/" + type_hash + "/" + qos;
129}
130
131/// 33-byte rmw_zenoh attachment payload sent with every put(). Layout:
132/// seq:i64 LE | ts:i64 LE | gid_len:u8(=16) | gid:[u8;16]. Constants are
133/// copied verbatim from zenoh_carla_bridge's utils.rs::generate_attachment.
134inline std::vector<uint8_t> zenoh_attachment() {
135 return {
136 1, 0, 0, 0, 0, 0, 0, 0,
137 0, 0, 0, 0, 0, 0, 0, 0,
138 16,
139 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
140 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
141 };
142}
143
144} // namespace ros2
145} // namespace carla
146
147#endif // CARLA_ROS2_MIDDLEWARE_ZENOH || CARLA_ROS2_MIDDLEWARE_TESTING
This file contains definitions of common data structures used in traffic manager.