CARLA
 
载入中...
搜索中...
未找到
CarlaTransformPublisher.cpp
浏览该文件的文档.
1#define _GLIBCXX_USE_CXX11_ABI 0
2
3#include "CarlaTransformPublisher.h"// 包含CarlaTransformPublisher类的声明
4
5#include <string>// 包含字符串处理功能
6// 包含CARLA ROS2类型定义和监听器类
9// 包含Fast-DDS(eProsima Fast RTPS的C++ API)的相关头文件
10#include <fastdds/dds/domain/DomainParticipant.hpp>
11#include <fastdds/dds/publisher/Publisher.hpp>
12#include <fastdds/dds/topic/Topic.hpp>
13#include <fastdds/dds/publisher/DataWriter.hpp>
14#include <fastdds/dds/topic/TypeSupport.hpp>
15// 包含Fast-DDS的QoS(服务质量)策略配置相关的头文件
16#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>
17#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
18#include <fastdds/dds/publisher/qos/PublisherQos.hpp>
19#include <fastdds/dds/topic/qos/TopicQos.hpp>
20// 包含Fast-RTPS的基础配置和QoS策略相关的头文件
21#include <fastrtps/attributes/ParticipantAttributes.h>
22#include <fastrtps/qos/QosPolicies.h>
23#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
24#include <fastdds/dds/publisher/DataWriterListener.hpp>
25
26/**
27 * @namespace carla::ros2
28 * @brief 命名空间,包含CARLA与ROS2桥接相关的类和功能。
29 */
30namespace carla {
31namespace ros2 {
32 /// 引入eprosima::fastdds::dds命名空间,并为其设置别名efd。
33 namespace efd = eprosima::fastdds::dds;
34 /// 为eprosima::fastrtps::types::ReturnCode_t类型设置别名erc。
35 using erc = eprosima::fastrtps::types::ReturnCode_t;
36 /**
37 * @struct CarlaTransformPublisherImpl
38 * @brief CarlaTransformPublisher的内部实现结构体。
39 *
40 * 该结构体包含了Fast-DDS相关的资源指针,以及用于发布变换信息的成员变量。
41 */
43 /// Fast-DDS的DomainParticipant指针。
44 efd::DomainParticipant* _participant { nullptr };
45 /// Fast-DDS的Publisher指针。
46 efd::Publisher* _publisher { nullptr };
47 /// Fast-DDS的Topic指针。
48 efd::Topic* _topic { nullptr };
49 /// Fast-DDS的DataWriter指针。
50 efd::DataWriter* _datawriter { nullptr };
51 /// Fast-DDS的TypeSupport,用于注册TFMessage类型。
52 efd::TypeSupport _type { new tf2_msgs::msg::TFMessagePubSubType() };
53 /// CarlaListener对象,用于监听CARLA的消息。
54 CarlaListener _listener {};
55 /// 存储要发布的TFMessage对象。
57 /// 上次的位置信息(x, y, z)。
58 float last_translation[3] = {0.0f};
59 /// 上次的旋转信息(roll, pitch, yaw,但通常使用四元数表示旋转更为准确)。
60 float last_rotation[3] = {0.0f};
61 /// 位置信息的ROS2消息表示。
63 /// 旋转信息的ROS2消息表示(使用四元数)。
65 };
66 /**
67 * @brief 初始化CarlaTransformPublisher对象
68 *
69 * 该函数负责初始化CarlaTransformPublisher对象,包括设置DomainParticipant、Publisher、Topic和DataWriter。
70 * 如果在初始化过程中遇到任何错误,函数将输出错误信息并返回false。
71 *
72 * @return bool 如果初始化成功,则返回true;否则返回false。
73 */
75 /**
76 * 检查_type是否为nullptr。如果是,则表示TypeSupport无效,输出错误信息并返回false。
77 */
78 if (_impl->_type == nullptr) {
79 std::cerr << "Invalid TypeSupport" << std::endl;
80 return false;
81 }
82 /**
83 * 设置DomainParticipant的QoS策略,并使用默认QoS创建一个DomainParticipant。
84 * 设置DomainParticipant的名称为_name。
85 */
86 efd::DomainParticipantQos pqos = efd::PARTICIPANT_QOS_DEFAULT;
87 pqos.name(_name);
88 auto factory = efd::DomainParticipantFactory::get_instance();
89 _impl->_participant = factory->create_participant(0, pqos);
90 /**
91 * 如果DomainParticipant创建失败,则输出错误信息并返回false。
92 */
93 if (_impl->_participant == nullptr) {
94 std::cerr << "Failed to create DomainParticipant" << std::endl;
95 return false;
96 }
97 /**
98 * 使用_type注册类型到DomainParticipant。
99 */
100 _impl->_type.register_type(_impl->_participant);
101 /**
102 * 设置Publisher的QoS策略,并使用默认QoS创建一个Publisher。
103 */
104 efd::PublisherQos pubqos = efd::PUBLISHER_QOS_DEFAULT;
105 _impl->_publisher = _impl->_participant->create_publisher(pubqos, nullptr);
106 /**
107 * 如果Publisher创建失败,则输出错误信息并返回false。
108 */
109 if (_impl->_publisher == nullptr) {
110 std::cerr << "Failed to create Publisher" << std::endl;
111 return false;
112 }
113 /**
114 * 设置Topic的QoS策略,并创建一个名为"rt/tf"的Topic。
115 */
116 efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
117 const std::string topic_name { "rt/tf" };
118 _impl->_topic = _impl->_participant->create_topic(topic_name, _impl->_type->getName(), tqos);
119 /**
120 * 如果Topic创建失败,则输出错误信息并返回false。
121 */
122 if (_impl->_topic == nullptr) {
123 std::cerr << "Failed to create Topic" << std::endl;
124 return false;
125 }
126 /**
127 * 设置DataWriter的QoS策略,并创建一个DataWriter。
128 * 将history_memory_policy设置为PREALLOCATED_WITH_REALLOC_MEMORY_MODE。
129 */
130 efd::DataWriterQos wqos = efd::DATAWRITER_QOS_DEFAULT;
131 wqos.endpoint().history_memory_policy = eprosima::fastrtps::rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
132 efd::DataWriterListener* listener = (efd::DataWriterListener*)_impl->_listener._impl.get();
133 _impl->_datawriter = _impl->_publisher->create_datawriter(_impl->_topic, wqos, listener);
134 /**
135 * 如果DataWriter创建失败,则输出错误信息并返回false。
136 */
137 if (_impl->_datawriter == nullptr) {
138 std::cerr << "Failed to create DataWriter" << std::endl;
139 return false;
140 }
141 /**
142 * 设置_frame_id为_name。
143 */
145 /**
146 * 初始化成功,返回true。
147 */
148 return true;
149 }
150 /**
151 * @brief 发布Carla的变换信息
152 *
153 * 该函数负责使用DataWriter发布_impl->_transform中的数据。根据返回码(ReturnCode_t)处理不同的错误情况,
154 * 并输出相应的错误信息。如果发布成功,则返回true;否则返回false。
155 *
156 * @return bool 发布成功返回true,否则返回false。
157 */
159 /**
160 * 声明一个InstanceHandle_t类型的变量instance_handle,用于接收write方法的返回值。
161 */
162 eprosima::fastrtps::rtps::InstanceHandle_t instance_handle;
163 eprosima::fastrtps::types::ReturnCode_t rcode = _impl->_datawriter->write(&_impl->_transform, instance_handle);
164 /**
165 * 调用DataWriter的write方法发布_impl->_transform数据,并获取返回码。
166 */
167 /**
168 * 根据返回码处理不同的错误情况。
169 */
170 if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
171 /**
172 * 发布成功,返回true。
173 */
174 return true;
175 }
176 if (rcode == erc::ReturnCodeValue::RETCODE_ERROR) {
177 /// @brief 通用错误
178 std::cerr << "RETCODE_ERROR" << std::endl;
179 return false;
180 }
181 if (rcode == erc::ReturnCodeValue::RETCODE_UNSUPPORTED) {
182 /// @brief 请求的操作不受支持
183 std::cerr << "RETCODE_UNSUPPORTED" << std::endl;
184 return false;
185 }
186 if (rcode == erc::ReturnCodeValue::RETCODE_BAD_PARAMETER) {
187 /// @brief 传递给函数的参数无效
188 std::cerr << "RETCODE_BAD_PARAMETER" << std::endl;
189 return false;
190 }
191 if (rcode == erc::ReturnCodeValue::RETCODE_PRECONDITION_NOT_MET) {
192 /// @brief 操作的前置条件未满足
193 std::cerr << "RETCODE_PRECONDITION_NOT_MET" << std::endl;
194 return false;
195 }
196 if (rcode == erc::ReturnCodeValue::RETCODE_OUT_OF_RESOURCES) {
197 /// @brief 系统资源不足,无法完成操作
198 std::cerr << "RETCODE_OUT_OF_RESOURCES" << std::endl;
199 return false;
200 }
201 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ENABLED) {
202 /// @brief 实体未启用,无法执行操作
203 std::cerr << "RETCODE_NOT_ENABLED" << std::endl;
204 return false;
205 }
206 if (rcode == erc::ReturnCodeValue::RETCODE_IMMUTABLE_POLICY) {
207 /// @brief 试图更改不可变的QoS策略
208 std::cerr << "RETCODE_IMMUTABLE_POLICY" << std::endl;
209 return false;
210 }
211 if (rcode == erc::ReturnCodeValue::RETCODE_INCONSISTENT_POLICY) {
212 /// @brief QoS策略不一致,无法设置
213 std::cerr << "RETCODE_INCONSISTENT_POLICY" << std::endl;
214 return false;
215 }
216 if (rcode == erc::ReturnCodeValue::RETCODE_ALREADY_DELETED) {
217 /// @brief 实体已被删除
218 std::cerr << "RETCODE_ALREADY_DELETED" << std::endl;
219 return false;
220 }
221 if (rcode == erc::ReturnCodeValue::RETCODE_TIMEOUT) {
222 /// @brief 操作超时
223 std::cerr << "RETCODE_TIMEOUT" << std::endl;
224 return false;
225 }
226 if (rcode == erc::ReturnCodeValue::RETCODE_NO_DATA) {
227 /// @brief 请求的数据不存在
228 std::cerr << "RETCODE_NO_DATA" << std::endl;
229 return false;
230 }
231 if (rcode == erc::ReturnCodeValue::RETCODE_ILLEGAL_OPERATION) {
232 /// @brief 执行了非法操作
233 std::cerr << "RETCODE_ILLEGAL_OPERATION" << std::endl;
234 return false;
235 }
236 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ALLOWED_BY_SECURITY) {
237 /// @brief 安全策略不允许执行此操作
238 std::cerr << "RETCODE_NOT_ALLOWED_BY_SECURITY" << std::endl;
239 return false;
240 }
241 /// @brief 如果返回码不是预定义的任何值,则输出"UNKNOWN"错误信息
242 std::cerr << "UNKNOWN" << std::endl;
243 return false;
244 }
245 /**
246 * @brief 设置CarlaTransformPublisher的数据
247 *
248 * 此函数用于更新位置和时间信息,并计算四元数旋转。
249 * 如果传入的位置或旋转与上一次的不同,则更新内部状态,并计算新的四元数旋转。
250 *
251 * @param seconds 时间戳的秒部分
252 * @param nanoseconds 时间戳的纳秒部分
253 * @param translation 指向包含x, y, z位置信息的浮点数组的指针
254 * @param rotation 指向包含绕x, y, z轴旋转角度(以度为单位)的浮点数组的指针
255 */
256 void CarlaTransformPublisher::SetData(int32_t seconds, uint32_t nanoseconds, const float* translation, const float* rotation) {
257 // 比较传入的位置和旋转与上一次的是否相同
258 int same_translation = std::memcmp(translation, _impl->last_translation, sizeof(float) * 3);
259 int same_rotation = std::memcmp(rotation, _impl->last_rotation, sizeof(float) * 3);
260 // 如果位置或旋转有变化,则更新内部状态
261 if (same_translation != 0 || same_rotation != 0) {
262 std::memcpy(_impl->last_translation, translation, sizeof(float) * 3);
263 std::memcpy(_impl->last_rotation, rotation, sizeof(float) * 3);
264 // 从数组中解包位置信息
265 const float tx = *translation++;
266 const float ty = *translation++;
267 const float tz = *translation++;
268 // 从数组中解包旋转信息,并转换为弧度
269 const float rx = ((*rotation++) * -1.0f) * (M_PIf32 / 180.0f);
270 const float ry = ((*rotation++) * -1.0f) * (M_PIf32 / 180.0f);
271 const float rz = *rotation++ * (M_PIf32 / 180.0f);
272 // 计算四元数的组成部分
273 const float cr = cosf(rz * 0.5f);
274 const float sr = sinf(rz * 0.5f);
275 const float cp = cosf(rx * 0.5f);
276 const float sp = sinf(rx * 0.5f);
277 const float cy = cosf(ry * 0.5f);
278 const float sy = sinf(ry * 0.5f);
279 // 更新位置信息(注意y轴方向取反)
280 _impl->vec_translation.x(tx);
281 _impl->vec_translation.y(-ty);
282 _impl->vec_translation.z(tz);
283 // 更新四元数旋转信息
284 _impl->vec_rotation.w(cr * cp * cy + sr * sp * sy);
285 _impl->vec_rotation.x(sr * cp * cy - cr * sp * sy);
286 _impl->vec_rotation.y(cr * sp * cy + sr * cp * sy);
287 _impl->vec_rotation.z(cr * cp * sy - sr * sp * cy);
288 }
289 // 设置时间戳
291 time.sec(seconds);
292 time.nanosec(nanoseconds);
293 // 创建消息头并设置时间戳和帧ID
294 std_msgs::msg::Header header;
295 header.stamp(std::move(time));
296 header.frame_id(_parent);
297 // 创建Transform消息并设置旋转和位置
299 t.rotation(_impl->vec_rotation);
300 t.translation(_impl->vec_translation);
301 // 创建TransformStamped消息并设置头信息、Transform和子帧ID
303 ts.header(std::move(header));
304 ts.transform(std::move(t));
306 // 更新内部存储的Transform集合
307 _impl->_transform.transforms({ts});
308 }
309 /**
310 * @brief CarlaTransformPublisher 类的构造函数
311 *
312 * 初始化 CarlaTransformPublisher 对象,并设置 ROS 名称和父帧ID。
313 *
314 * @param ros_name ROS 节点名称
315 * @param parent 父帧ID
316 */
317 CarlaTransformPublisher::CarlaTransformPublisher(const char* ros_name, const char* parent) :
318 _impl(std::make_shared<CarlaTransformPublisherImpl>()) {
319 _name = ros_name;
320 _parent = parent;
321 }
322 /**
323 * @brief CarlaTransformPublisher 类的析构函数
324 *
325 * 清理资源,删除与 DDS(Data Distribution Service)相关的对象。
326 */
328 if (!_impl)
329 return;
330 // 删除 DataWriter
331 if (_impl->_datawriter)
332 _impl->_publisher->delete_datawriter(_impl->_datawriter);
333 // 删除 Publisher
334 if (_impl->_publisher)
335 _impl->_participant->delete_publisher(_impl->_publisher);
336 // 删除 Topic
337 if (_impl->_topic)
338 _impl->_participant->delete_topic(_impl->_topic);
339 // 删除 Participant
340 if (_impl->_participant)
341 efd::DomainParticipantFactory::get_instance()->delete_participant(_impl->_participant);
342 }
343 /**
344 * @brief CarlaTransformPublisher 类的拷贝构造函数
345 *
346 * 创建一个与现有对象相同的 CarlaTransformPublisher 对象。
347 * 注意:这里浅拷贝了 _impl 指针,假设 CarlaTransformPublisherImpl 类是正确管理其生命周期的。
348 *
349 * @param other 要拷贝的对象
350 */
352 _frame_id = other._frame_id;
353 _name = other._name;
354 _parent = other._parent;
355 _impl = other._impl;// 浅拷贝 _impl 指针
356 }
357 /**
358 * @brief 赋值运算符重载
359 *
360 * 将现有对象的值赋给另一个 CarlaTransformPublisher 对象。
361 * 注意:这里浅拷贝了 _impl 指针。
362 *
363 * @param other 要赋值的对象
364 * @return 引用到当前对象
365 */
367 _frame_id = other._frame_id;
368 _name = other._name;
369 _parent = other._parent;
370 _impl = other._impl;// 浅拷贝 _impl 指针
371
372 return *this;
373 }
374 /**
375 * @brief CarlaTransformPublisher 类的移动构造函数
376 *
377 * 创建一个新的 CarlaTransformPublisher 对象,并将现有对象的资源移动到新对象中。
378 *
379 * @param other 要移动的对象
380 */
382 _frame_id = std::move(other._frame_id);
383 _name = std::move(other._name);
384 _parent = std::move(other._parent);
385 _impl = std::move(other._impl);// 移动 _impl 指针
386 }
387 /**
388 * @brief 移动赋值运算符重载
389 *
390 * 将现有对象的资源移动到另一个 CarlaTransformPublisher 对象。
391 *
392 * @param other 要移动赋值的对象
393 * @return 引用到当前对象
394 */
396 _frame_id = std::move(other._frame_id);
397 _name = std::move(other._name);
398 _parent = std::move(other._parent);
399 _impl = std::move(other._impl);// 移动 _impl 指针
400
401 return *this;
402 }
403}
404}
此类表示用户在IDL文件中定义的Time结构。
eProsima_user_DllExport void nanosec(uint32_t _nanosec)
此函数设置成员nanosec的值。
Definition Time.cpp:183
eProsima_user_DllExport void sec(int32_t _sec)
此函数设置成员sec的值。
Definition Time.cpp:152
const std::string & parent() const
CarlaTransformPublisher类继承自CarlaPublisher,用于在CARLA中发布变换信息到ROS2。
bool Init()
初始化函数,用于初始化CarlaTransformPublisher对象。
std::shared_ptr< CarlaTransformPublisherImpl > _impl
指向CarlaTransformPublisherImpl的智能指针,用于隐藏实现细节。
void SetData(int32_t seconds, uint32_t nanoseconds, const float *translation, const float *rotation)
设置变换数据的函数。
CarlaTransformPublisher & operator=(const CarlaTransformPublisher &)
拷贝赋值运算符,将另一个CarlaTransformPublisher对象的内容复制到当前对象。
~CarlaTransformPublisher()
析构函数,释放CarlaTransformPublisher对象占用的资源。
CarlaTransformPublisher(const char *ros_name="", const char *parent="")
构造函数,初始化CarlaTransformPublisher对象。
bool Publish()
发布函数,用于将变换信息发布到ROS2。
This class represents the structure Quaternion defined by the user in the IDL file.
Definition Quaternion.h:71
此类表示用户在 IDL 文件中定义的 TransformStamped 结构。 <>
eProsima_user_DllExport void transform(const geometry_msgs::msg::Transform &_transform)
此函数复制成员 transform 的值。
eProsima_user_DllExport void child_frame_id(const std::string &_child_frame_id)
此函数复制成员 child_frame_id 的值。
eProsima_user_DllExport void header(const std_msgs::msg::Header &_header)
此函数复制成员 header 的值。
此类表示用户在IDL文件中定义的Transform结构。
eProsima_user_DllExport void translation(const geometry_msgs::msg::Vector3 &_translation)
此函数用于拷贝成员变量translation的值,将传入的新值拷贝到成员translation中。
eProsima_user_DllExport void rotation(const geometry_msgs::msg::Quaternion &_rotation)
此函数用于拷贝成员变量rotation的值,将传入的新值拷贝到成员rotation中。
此类表示用户在 IDL 文件中定义的 Vector3 结构。 <>
Definition Vector3.h:72
This class represents the TopicDataType of the type TFMessage defined by the user in the IDL file.
Carlaе·عܵռ
eprosima::fastrtps::types::ReturnCode_t erc
@using erc
CARLA模拟器的主命名空间。
Definition Carla.cpp:139
CarlaTransformPublisher的内部实现结构体。
geometry_msgs::msg::Vector3 vec_translation
位置信息的ROS2消息表示。
efd::DataWriter * _datawriter
Fast-DDS的DataWriter指针。
CarlaListener _listener
CarlaListener对象,用于监听CARLA的消息。
tf2_msgs::msg::TFMessage _transform
存储要发布的TFMessage对象。
efd::TypeSupport _type
Fast-DDS的TypeSupport,用于注册TFMessage类型。
efd::DomainParticipant * _participant
Fast-DDS的DomainParticipant指针。
efd::Publisher * _publisher
Fast-DDS的Publisher指针。
efd::Topic * _topic
Fast-DDS的Topic指针。
float last_rotation[3]
上次的旋转信息(roll, pitch, yaw,但通常使用四元数表示旋转更为准确)。
float last_translation[3]
上次的位置信息(x, y, z)。
geometry_msgs::msg::Quaternion vec_rotation
旋转信息的ROS2消息表示(使用四元数)。