CARLA
 
载入中...
搜索中...
未找到
CarlaClockPublisher.cpp
浏览该文件的文档.
1#define _GLIBCXX_USE_CXX11_ABI 0
2//定义宏,设置使用的C++11 ABI版本为0
3/// @file CarlaClockPublisher.cpp
4/// @brief CarlaClockPublisher 类的实现文件,负责发布CARLA的时钟信息到ROS2系统。
5#include "CarlaClockPublisher.h"/// @brief 包含 CarlaClockPublisher 类的声明。
6
7#include <string>/// @brief 包含标准字符串库,用于处理字符串数据。
8// CARLA ROS2 类型支持
9#include "carla/ros2/types/ClockPubSubTypes.h"/// @brief 包含 CARLA ROS2 时钟消息的类型支持。
10#include "carla/ros2/listeners/CarlaListener.h"/// @brief 包含 CARLA ROS2 监听器的基类声明。
11// Fast-DDS 相关头文件
12#include <fastdds/dds/domain/DomainParticipant.hpp>/// @brief 包含 Fast-DDS 域参与者的类声明,用于创建、删除和管理域中的其他实体。
13#include <fastdds/dds/publisher/Publisher.hpp>/// @brief 包含 Fast-DDS 发布者的类声明,用于将数据写入到指定的主题。
14#include <fastdds/dds/topic/Topic.hpp>/// @brief 包含 Fast-DDS 主题的类声明,用于定义数据的类型和名称。
15#include <fastdds/dds/publisher/DataWriter.hpp>/// @brief 包含 Fast-DDS 数据写入器的类声明,用于将数据写入到主题。
16#include <fastdds/dds/topic/TypeSupport.hpp>/// @brief 包含 Fast-DDS 类型支持的类声明,用于为特定类型提供序列化和反序列化功能。
17
18#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>/// @brief 包含 Fast-DDS 域参与者QoS策略的类声明。
19#include <fastdds/dds/domain/DomainParticipantFactory.hpp>/// @brief 包含 Fast-DDS 域参与者工厂的类声明,用于创建域参与者。
20#include <fastdds/dds/publisher/qos/PublisherQos.hpp>/// @brief 包含 Fast-DDS 发布者QoS策略的类声明。
21#include <fastdds/dds/topic/qos/TopicQos.hpp> /// @brief 包含 Fast-DDS 主题QoS策略的类声明。
22// Fast-RTPS(实时发布订阅)相关头文件
23#include <fastrtps/attributes/ParticipantAttributes.h>/// @brief 包含 Fast-RTPS 参与者属性的类声明,用于配置参与者的网络属性。
24#include <fastrtps/qos/QosPolicies.h>/// @brief 包含 Fast-RTPS QoS策略的类声明,用于配置发布者和订阅者的服务质量。
25#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>/// @brief 包含 Fast-DDS 数据写入器QoS策略的类声明。
26#include <fastdds/dds/publisher/DataWriterListener.hpp>/// @brief 包含 Fast-DDS 数据写入器监听器的类声明,用于接收数据写入事件。
27
28/**
29 * @namespace carla::ros2
30 * @brief 此命名空间包含了CARLA与ROS 2集成的相关功能。
31 */
32namespace carla {
33namespace ros2 {
34 /**
35 * @namespace efd
36 * @brief 别名,代表eprosima::fastdds::dds命名空间,用于简化Fast DDS相关类型的引用。
37 */
38 namespace efd = eprosima::fastdds::dds;
39 /**
40 * @using erc
41 * @brief 别名,代表eprosima::fastrtps::types::ReturnCode_t类型,用于简化返回码类型的引用。
42 */
43 using erc = eprosima::fastrtps::types::ReturnCode_t;
44 /**
45 * @struct CarlaClockPublisherImpl
46 * @brief CarlaClockPublisher的内部实现结构体,用于封装与Fast DDS相关的资源。
47 */
49 /**
50 * @brief 指向DomainParticipant的指针,用于管理DDS域中的参与者。
51 */
52 efd::DomainParticipant* _participant { nullptr };
53 /**
54 * @brief 指向Publisher的指针,用于发布数据。
55 */
56 efd::Publisher* _publisher { nullptr };
57 /**
58 * @brief 指向Topic的指针,用于定义数据的主题。
59 */
60 efd::Topic* _topic { nullptr };
61 /**
62 * @brief 指向DataWriter的指针,用于写入数据到指定的Topic。
63 */
64 efd::DataWriter* _datawriter { nullptr };
65 /**
66 * @brief TypeSupport对象,用于注册和识别消息类型。
67 */
68 efd::TypeSupport _type { new rosgraph::msg::ClockPubSubType() };
69 /**
70 * @brief CarlaListener对象,用于监听DDS事件。
71 */
72 CarlaListener _listener {};
73 /**
74 * @brief 存储Clock消息的变量。
75 */
77 };
78 /**
79 * @brief 初始化CarlaClockPublisher对象。
80 *
81 * 此函数负责创建并配置DDS中的DomainParticipant、Publisher、Topic和DataWriter。
82 *
83 * @return 如果初始化成功,则返回true;否则返回false。
84 */
86 // 检查TypeSupport是否有效
87 if (_impl->_type == nullptr) {
88 std::cerr << "Invalid TypeSupport" << std::endl;
89 return false;
90 }
91 // 设置DomainParticipant的QoS策略为默认值,并设置其名称为_name,然后创建DomainParticipant
92 efd::DomainParticipantQos pqos = efd::PARTICIPANT_QOS_DEFAULT;
93 pqos.name(_name);
94 auto factory = efd::DomainParticipantFactory::get_instance();
95 _impl->_participant = factory->create_participant(0, pqos);
96 if (_impl->_participant == nullptr) {
97 std::cerr << "Failed to create DomainParticipant" << std::endl;
98 return false;
99 }
100// 如果创建DomainParticipant失败,则输出错误信息并返回false
101 // 注册消息类型到DomainParticipant
102 _impl->_type.register_type(_impl->_participant);
103 // 设置Publisher的QoS策略并创建Publisher
104 efd::PublisherQos pubqos = efd::PUBLISHER_QOS_DEFAULT;
105 _impl->_publisher = _impl->_participant->create_publisher(pubqos, nullptr);
106 if (_impl->_publisher == nullptr) {
107 std::cerr << "Failed to create Publisher" << std::endl;
108 return false;
109 // 如果创建Publisher失败,则输出错误信息并返回false
110 }
111 // 设置Topic的QoS策略为默认值,定义主题名称为"rt/clock",然后创建Topic
112 efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
113 const std::string topic_name { "rt/clock" };
114 _impl->_topic = _impl->_participant->create_topic(topic_name, _impl->_type->getName(), tqos);
115 if (_impl->_topic == nullptr) {
116 std::cerr << "Failed to create Topic" << std::endl;
117 return false;
118// 如果创建Topic失败,则输出错误信息并返回false
119 }
120 // 设置DataWriter的QoS策略为默认值,获取对应的监听器,然后创建DataWriter
121 efd::DataWriterQos wqos = efd::DATAWRITER_QOS_DEFAULT;
122 efd::DataWriterListener* listener = (efd::DataWriterListener*)_impl->_listener._impl.get();
123 _impl->_datawriter = _impl->_publisher->create_datawriter(_impl->_topic, wqos, listener);
124 if (_impl->_datawriter == nullptr) {
125 std::cerr << "Failed to create DataWriter" << std::endl;
126 return false;
127// 如果创建DataWriter失败,则输出错误信息并返回false
128 }
129 // 设置帧ID
131 return true;
132 }
133 /**
134 * @brief 发布时钟数据的方法
135 *
136 * 该方法尝试通过Fast-RTPS发布时钟数据。
137 * 如果发布成功,则返回true;否则,根据返回码输出相应的错误信息,并返回false。
138 *
139 * @return bool 发布成功返回true,否则返回false。
140 */
142// 创建一个实例句柄,用于标识数据实例(在Fast-RTPS相关操作中使用)
143 eprosima::fastrtps::rtps::InstanceHandle_t instance_handle;
144// 通过数据写入器尝试写入时钟数据,获取返回码
145 eprosima::fastrtps::types::ReturnCode_t rcode = _impl->_datawriter->write(&_impl->_clock, instance_handle);
146 // 根据返回码判断是否发布成功,如果返回码为RETCODE_OK表示发布成功,直接返回true
147 if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
148 return true;
149 }
150// 如果返回码为RETCODE_ERROR,表示出现错误,输出相应错误信息并返回false
151 if (rcode == erc::ReturnCodeValue::RETCODE_ERROR) {
152 std::cerr << "RETCODE_ERROR" << std::endl;
153 return false;
154 }
155 if (rcode == erc::ReturnCodeValue::RETCODE_UNSUPPORTED) {
156 std::cerr << "RETCODE_UNSUPPORTED" << std::endl;
157 return false;
158 // 如果返回码为RETCODE_UNSUPPORTED,表示操作不被支持,输出相应错误信息并返回false
159 }
160 if (rcode == erc::ReturnCodeValue::RETCODE_BAD_PARAMETER) {
161 std::cerr << "RETCODE_BAD_PARAMETER" << std::endl;
162 return false;
163// 如果返回码为RETCODE_BAD_PARAMETER,表示参数错误,输出相应错误信息并返回false
164 }
165 if (rcode == erc::ReturnCodeValue::RETCODE_PRECONDITION_NOT_MET) {
166 std::cerr << "RETCODE_PRECONDITION_NOT_MET" << std::endl;
167 return false;
168// 如果返回码为RETCODE_PRECONDITION_NOT_MET,表示前置条件未满足,输出相应错误信息并返回false
169 }
170 if (rcode == erc::ReturnCodeValue::RETCODE_OUT_OF_RESOURCES) {
171 std::cerr << "RETCODE_OUT_OF_RESOURCES" << std::endl;
172 return false;
173// 如果返回码为RETCODE_OUT_OF_RESOURCES,表示资源不足,输出相应错误信息并返回false
174 }
175 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ENABLED) {
176 std::cerr << "RETCODE_NOT_ENABLED" << std::endl;
177 return false;
178// 如果返回码为RETCODE_NOT_ENABLED,表示未启用相关功能,输出相应错误信息并返回false
179 }
180 if (rcode == erc::ReturnCodeValue::RETCODE_IMMUTABLE_POLICY) {
181 std::cerr << "RETCODE_IMMUTABLE_POLICY" << std::endl;
182 return false;
183 // 如果返回码为RETCODE_IMMUTABLE_POLICY,表示策略不可变,输出相应错误信息并返回false
184 }
185 if (rcode == erc::ReturnCodeValue::RETCODE_INCONSISTENT_POLICY) {
186 std::cerr << "RETCODE_INCONSISTENT_POLICY" << std::endl;
187 return false;
188// 如果返回码为RETCODE_INCONSISTENT_POLICY,表示策略不一致,输出相应错误信息并返回false
189 }
190 if (rcode == erc::ReturnCodeValue::RETCODE_ALREADY_DELETED) {
191 std::cerr << "RETCODE_ALREADY_DELETED" << std::endl;
192 return false;
193// 如果返回码为RETCODE_ALREADY_DELETED,表示已经被删除,输出相应错误信息并返回false
194 }
195 if (rcode == erc::ReturnCodeValue::RETCODE_TIMEOUT) {
196 std::cerr << "RETCODE_TIMEOUT" << std::endl;
197 return false;
198 // 如果返回码为RETCODE_TIMEOUT,表示操作超时,输出相应错误信息并返回false
199 }
200 if (rcode == erc::ReturnCodeValue::RETCODE_NO_DATA) {
201 std::cerr << "RETCODE_NO_DATA" << std::endl;
202 return false;
203// 如果返回码为RETCODE_NO_DATA,表示没有数据,输出相应错误信息并返回false
204 }
205 if (rcode == erc::ReturnCodeValue::RETCODE_ILLEGAL_OPERATION) {
206 std::cerr << "RETCODE_ILLEGAL_OPERATION" << std::endl;
207 return false;
208// 如果返回码为RETCODE_ILLEGAL_OPERATION,表示非法操作,输出相应错误信息并返回false
209 }
210 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ALLOWED_BY_SECURITY) {
211 std::cerr << "RETCODE_NOT_ALLOWED_BY_SECURITY" << std::endl;
212 return false;
213 // 如果返回码为RETCODE_NOT_ALLOWED_BY_SECURITY,表示安全策略不允许,输出相应错误信息并返回false
214 }
215 std::cerr << "UNKNOWN" << std::endl;
216 return false;
217 }
218 /**
219 * @brief 设置时钟数据的方法
220 *
221 * 该方法用于设置时钟数据的秒和纳秒部分。
222 *
223 * @param sec 秒部分
224 * @param nanosec 纳秒部分
225 */
226 void CarlaClockPublisher::SetData(int32_t sec, uint32_t nanosec) {
227 _impl->_clock.clock().sec(sec);
228 _impl->_clock.clock().nanosec(nanosec);
229 }
230 /**
231 * @brief CarlaClockPublisher的构造函数
232 *
233 * 初始化CarlaClockPublisher对象,包括设置名称、父对象,并创建实现类的实例。
234 *
235 * @param ros_name ROS节点名称
236 * @param parent 父对象名称
237 */
238 CarlaClockPublisher::CarlaClockPublisher(const char* ros_name, const char* parent) :
239 _impl(std::make_shared<CarlaClockPublisherImpl>()) {
240 _name = ros_name;
241 _parent = parent;
242 }
243 /**
244 * @brief CarlaClockPublisher的析构函数
245 *
246 * 释放CarlaClockPublisher对象占用的资源,包括删除数据写入器、发布者、主题和参与者。
247 */
249 if (!_impl)
250 return;
251
252 if (_impl->_datawriter)
253 _impl->_publisher->delete_datawriter(_impl->_datawriter);
254
255 if (_impl->_publisher)
256 _impl->_participant->delete_publisher(_impl->_publisher);
257
258 if (_impl->_topic)
259 _impl->_participant->delete_topic(_impl->_topic);
260
261 if (_impl->_participant)
262 efd::DomainParticipantFactory::get_instance()->delete_participant(_impl->_participant);
263 }
264 /**
265 * @brief CarlaClockPublisher的拷贝构造函数
266 *
267 * 创建一个新的CarlaClockPublisher对象,作为现有对象的副本。
268 *
269 * @param other 现有对象
270 */
272 _frame_id = other._frame_id;
273 _name = other._name;
274 _parent = other._parent;
275 _impl = other._impl;
276 }
277 /**
278 * @brief 赋值运算符重载
279 *
280 * 将现有对象的值赋给当前对象。
281 *
282 * @param other 现有对象
283 * @return CarlaClockPublisher& 当前对象的引用
284 */
286 _frame_id = other._frame_id;
287 _name = other._name;
288 _parent = other._parent;
289 _impl = other._impl;
290
291 return *this;
292 }
293 /**
294 * @brief CarlaClockPublisher的移动构造函数
295 *
296 * 创建一个新的CarlaClockPublisher对象,通过移动现有对象的资源来初始化。
297 *
298 * @param other 现有对象
299 */
301 _frame_id = std::move(other._frame_id);
302 _name = std::move(other._name);
303 _parent = std::move(other._parent);
304 _impl = std::move(other._impl);
305 }
306 /**
307 * @brief 移动赋值运算符重载
308 *
309 * 通过移动现有对象的资源来更新当前对象。
310 *
311 * @param other 现有对象
312 * @return CarlaClockPublisher& 当前对象的引用
313 */
315 _frame_id = std::move(other._frame_id);
316 _name = std::move(other._name);
317 _parent = std::move(other._parent);
318 _impl = std::move(other._impl);
319
320 return *this;
321 }
322}
323}
用于发布CARLA时钟信息的ROS 2发布者类。
CarlaClockPublisher(const char *ros_name="", const char *parent="")
构造函数,初始化CarlaClockPublisher。
~CarlaClockPublisher()
析构函数,清理资源并释放内部实现。
CarlaClockPublisher & operator=(const CarlaClockPublisher &)
赋值运算符。
std::shared_ptr< CarlaClockPublisherImpl > _impl
指向内部实现结构体的智能指针。
bool Init()
初始化发布者。
void SetData(int32_t sec, uint32_t nanosec)
设置要发布的时钟数据。
bool Publish()
发布时钟信息。
const std::string & parent() const
此类表示用户在 IDL 文件中定义的类型 Clock 的 TopicDataType。 <>
This class represents the structure Clock defined by the user in the IDL file.
Definition Clock.h:74
eprosima::fastrtps::types::ReturnCode_t erc
@using erc
CARLA模拟器的主命名空间。
Definition Carla.cpp:139
CarlaClockPublisher的内部实现结构体,用于封装与Fast DDS相关的资源。
CarlaListener _listener
CarlaListener对象,用于监听DDS事件。
efd::Publisher * _publisher
指向Publisher的指针,用于发布数据。
efd::TypeSupport _type
TypeSupport对象,用于注册和识别消息类型。
rosgraph::msg::Clock _clock
存储Clock消息的变量。
efd::DomainParticipant * _participant
指向DomainParticipant的指针,用于管理DDS域中的参与者。
efd::Topic * _topic
指向Topic的指针,用于定义数据的主题。
efd::DataWriter * _datawriter
指向DataWriter的指针,用于写入数据到指定的Topic。