CARLA
 
载入中...
搜索中...
未找到
CarlaEgoVehicleControlSubscriber.cpp
浏览该文件的文档.
1#define _GLIBCXX_USE_CXX11_ABI 0
2
3#include "CarlaEgoVehicleControlSubscriber.h"// 引入Carla自我车辆控制订阅者的头文件
4
5#include "carla/ros2/types/CarlaEgoVehicleControl.h"// 引入Carla自我车辆控制信息的消息类型
6#include "carla/ros2/types/CarlaEgoVehicleControlPubSubTypes.h"// 引入Carla自我车辆控制信息的PubSub类型
7#include "carla/ros2/listeners/CarlaSubscriberListener.h"// 引入Carla订阅者监听器
8// 引入Fast-DDS相关的头文件
9#include <fastdds/dds/domain/DomainParticipant.hpp>// 引入域参与者类
10#include <fastdds/dds/subscriber/Subscriber.hpp>// 引入订阅者类
11#include <fastdds/dds/topic/Topic.hpp>// 引入主题类
12#include <fastdds/dds/subscriber/DataReader.hpp> // 引入数据读取器类
13#include <fastdds/dds/topic/TypeSupport.hpp>// 引入类型支持类
14#include <fastdds/dds/subscriber/SampleInfo.hpp>// 引入样本信息类
15// 引入Fast-DDS QOS相关的头文件
16#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>// 引入域参与者QOS类
17#include <fastdds/dds/domain/DomainParticipantFactory.hpp>// 引入域参与者工厂类
18#include <fastdds/dds/subscriber/qos/SubscriberQos.hpp>// 引入订阅者QOS类
19#include <fastdds/dds/topic/qos/TopicQos.hpp>// 引入主题QOS类
20// 引入Fast-RTPS属性与QOS策略相关的头文件
21#include <fastrtps/attributes/ParticipantAttributes.h>// 引入参与者属性类
22#include <fastrtps/qos/QosPolicies.h>// 引入QOS策略类
23#include <fastdds/dds/subscriber/qos/DataReaderQos.hpp>// 引入数据读取器QOS类
24#include <fastdds/dds/subscriber/DataReaderListener.hpp>// 引入数据读取器监听器类
25
26/**
27 * @namespace carla::ros2
28 * @brief 定义了CARLA与ROS 2集成的相关代码。
29 */
30namespace carla {
31namespace ros2 {
32 /**
33 * @brief 引入并定义了一些别名,以便简化代码中的类型引用。
34 *
35 * - `efd` 是 `eprosima::fastdds::dds` 的别名,用于DDS(Data Distribution Service)通信。
36 * - `erc` 是 `eprosima::fastrtps::types::ReturnCode_t` 的别名,用于表示Fast RTPS的返回码类型。
37 */
38 namespace efd = eprosima::fastdds::dds;
39 using erc = eprosima::fastrtps::types::ReturnCode_t;
40 /**
41 * @struct CarlaEgoVehicleControlSubscriberImpl
42 * @brief CarlaEgoVehicleControlSubscriber的内部实现结构体。
43 *
44 * 包含了DDS订阅者所需的所有成员变量,用于接收和处理CARLA的EgoVehicleControl消息。
45 */
47 /**
48 * @brief DDS域参与者指针。
49 */
50 efd::DomainParticipant* _participant { nullptr };
51 /**
52 * @brief DDS订阅者指针。
53 */
54 efd::Subscriber* _subscriber { nullptr };
55 /**
56 * @brief DDS主题指针。
57 */
58 efd::Topic* _topic { nullptr };
59 /**
60 * @brief DDS数据读取器指针。
61 */
62 efd::DataReader* _datareader { nullptr };
63 /**
64 * @brief DDS类型支持,用于注册消息类型。
65 */
67 /**
68 * @brief 订阅者监听器,用于处理接收到的消息。
69 */
71 /**
72 * @brief 存储接收到的CARLA EgoVehicleControl消息。
73 */
75 /**
76 * @brief 转换为内部使用的VehicleControl结构体。
77 */
79 /**
80 * @brief 标记是否有新的消息到达。
81 */
82 bool _new_message {false};
83 /**
84 * @brief 标记订阅者是否仍然活跃。
85 */
86 bool _alive {true};
87 /**
88 * @brief 与车辆控制相关的指针(具体类型未在代码中定义)。
89 */
90 void* _vehicle {nullptr};
91 };
92 /**
93 * @brief 初始化CARLA EgoVehicleControl消息的订阅者。
94 *
95 * @return 初始化成功返回true,否则返回false。
96 */
98 /**
99 * @brief 检查类型支持是否有效。
100 */
101 if (_impl->_type == nullptr) {
102 std::cerr << "Invalid TypeSupport" << std::endl;
103 return false;
104 }
105 /**
106 * @brief 设置域参与者的QoS(Quality of Service)并创建域参与者。
107 */
108 efd::DomainParticipantQos pqos = efd::PARTICIPANT_QOS_DEFAULT;
109 pqos.name(_name);
110 auto factory = efd::DomainParticipantFactory::get_instance();
111 _impl->_participant = factory->create_participant(0, pqos);
112 if (_impl->_participant == nullptr) {
113 std::cerr << "Failed to create DomainParticipant" << std::endl;
114 return false;
115 }
116 /**
117 * @brief 注册消息类型。
118 */
119 _impl->_type.register_type(_impl->_participant);
120 /**
121 * @brief 设置订阅者的QoS并创建订阅者。
122 */
123 efd::SubscriberQos subqos = efd::SUBSCRIBER_QOS_DEFAULT;
124 _impl->_subscriber = _impl->_participant->create_subscriber(subqos, nullptr);
125 if (_impl->_subscriber == nullptr) {
126 std::cerr << "Failed to create Subscriber" << std::endl;
127 return false;
128 }
129 /**
130 * @brief 设置主题的QoS并创建主题。
131 */
132 efd::TopicQos tqos = efd::TOPIC_QOS_DEFAULT;
133 const std::string base { "rt/carla/" };
134 const std::string publisher_type {"/vehicle_control_cmd"};
135 std::string topic_name = base;
136 if (!_parent.empty())
137 topic_name += _parent + "/";
138 topic_name += _name;
139 topic_name += publisher_type;
140 _impl->_topic = _impl->_participant->create_topic(topic_name, _impl->_type->getName(), tqos);
141 if (_impl->_topic == nullptr) {
142 std::cerr << "Failed to create Topic" << std::endl;
143 return false;
144 }
145 /**
146 * @brief 设置数据读取器的QoS并创建数据读取器。
147 */
148 efd::DataReaderQos rqos = efd::DATAREADER_QOS_DEFAULT;
149 efd::DataReaderListener* listener = (efd::DataReaderListener*)_impl->_listener._impl.get();
150 _impl->_datareader = _impl->_subscriber->create_datareader(_impl->_topic, rqos, listener);
151 if (_impl->_datareader == nullptr) {
152 std::cerr << "Failed to create DataReader" << std::endl;
153 return false;
154 }
155 return true;
156 }
157 /**
158 * @brief 读取并处理来自数据读取器的样本
159 *
160 * 该函数尝试从内部数据读取器中获取下一个样本,并根据返回的代码执行相应的操作。
161 * 如果成功获取样本,则返回true;否则,根据错误代码打印错误信息并返回false。
162 *
163 * @return bool 如果成功获取样本,则返回true;否则返回false。
164 */
166 efd::SampleInfo info;// 用于存储样本信息的结构体
167 // 尝试从数据读取器中获取下一个样本
168 eprosima::fastrtps::types::ReturnCode_t rcode = _impl->_datareader->take_next_sample(&_impl->_event, &info);
169 // 根据返回的代码执行相应的操作
170 if (rcode == erc::ReturnCodeValue::RETCODE_OK) {
171 /// @todo 成功获取样本,返回true
172 return true;
173 }
174 if (rcode == erc::ReturnCodeValue::RETCODE_ERROR) {
175 /// @todo 打印错误代码"RETCODE_ERROR"并返回false
176 std::cerr << "RETCODE_ERROR" << std::endl;
177 return false;
178 }
179 if (rcode == erc::ReturnCodeValue::RETCODE_UNSUPPORTED) {
180 /// @todo 打印错误代码"RETCODE_UNSUPPORTED"并返回false
181 std::cerr << "RETCODE_UNSUPPORTED" << std::endl;
182 return false;
183 }
184 if (rcode == erc::ReturnCodeValue::RETCODE_BAD_PARAMETER) {
185 /// @todo 打印错误代码"RETCODE_BAD_PARAMETER"并返回false
186 std::cerr << "RETCODE_BAD_PARAMETER" << std::endl;
187 return false;
188 }
189 if (rcode == erc::ReturnCodeValue::RETCODE_PRECONDITION_NOT_MET) {
190 /// @todo 打印错误代码"RETCODE_PRECONDITION_NOT_MET"并返回false
191 std::cerr << "RETCODE_PRECONDITION_NOT_MET" << std::endl;
192 return false;
193 }
194 if (rcode == erc::ReturnCodeValue::RETCODE_OUT_OF_RESOURCES) {
195 /// @todo 打印错误代码"RETCODE_OUT_OF_RESOURCES"并返回false
196 std::cerr << "RETCODE_OUT_OF_RESOURCES" << std::endl;
197 return false;
198 }
199 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ENABLED) {
200 /// @todo 打印错误代码"RETCODE_NOT_ENABLED"并返回false
201 std::cerr << "RETCODE_NOT_ENABLED" << std::endl;
202 return false;
203 }
204 if (rcode == erc::ReturnCodeValue::RETCODE_IMMUTABLE_POLICY) {
205 /// @todo 打印错误代码"RETCODE_IMMUTABLE_POLICY"并返回false
206 std::cerr << "RETCODE_IMMUTABLE_POLICY" << std::endl;
207 return false;
208 }
209 if (rcode == erc::ReturnCodeValue::RETCODE_INCONSISTENT_POLICY) {
210 /// @todo 打印错误代码"RETCODE_INCONSISTENT_POLICY"并返回false
211 std::cerr << "RETCODE_INCONSISTENT_POLICY" << std::endl;
212 return false;
213 }
214 if (rcode == erc::ReturnCodeValue::RETCODE_ALREADY_DELETED) {
215 /// @todo 打印错误代码"RETCODE_ALREADY_DELETED"并返回false
216 std::cerr << "RETCODE_ALREADY_DELETED" << std::endl;
217 return false;
218 }
219 if (rcode == erc::ReturnCodeValue::RETCODE_TIMEOUT) {
220 /// @todo 打印错误代码"RETCODE_TIMEOUT"并返回false
221 std::cerr << "RETCODE_TIMEOUT" << std::endl;
222 return false;
223 }
224 if (rcode == erc::ReturnCodeValue::RETCODE_NO_DATA) {
225 /// @todo 打印错误代码"RETCODE_NO_DATA"并返回false
226 std::cerr << "RETCODE_NO_DATA" << std::endl;
227 return false;
228 }
229 if (rcode == erc::ReturnCodeValue::RETCODE_ILLEGAL_OPERATION) {
230 /// @todo 打印错误代码"RETCODE_ILLEGAL_OPERATION"并返回false
231 std::cerr << "RETCODE_ILLEGAL_OPERATION" << std::endl;
232 return false;
233 }
234 if (rcode == erc::ReturnCodeValue::RETCODE_NOT_ALLOWED_BY_SECURITY) {
235 /// @todo 打印错误代码"RETCODE_NOT_ALLOWED_BY_SECURITY"并返回false
236 std::cerr << "RETCODE_NOT_ALLOWED_BY_SECURITY" << std::endl;
237 return false;
238 }
239 /// @todo 打印未知错误代码"UNKNOWN"并返回false
240 std::cerr << "UNKNOWN" << std::endl;
241 return false;
242 }
243 /**
244 * @brief 将车辆控制信息转发给内部实现。
245 *
246 * 该函数将传入的车辆控制信息(VehicleControl)保存到内部实现对象的对应成员变量中,
247 * 并标记有新的消息到达。
248 *
249 * @param control 车辆控制信息。
250 */
252 _impl->_control = control;
253 _impl->_new_message = true;
254 }
255 /**
256 * @brief 销毁订阅者。
257 *
258 * 该函数将内部实现对象的存活标志设置为false,用于通知其他部分该订阅者已经不再活跃。
259 */
263 /**
264 * @brief 获取最新的车辆控制信息。
265 *
266 * 该函数返回内部实现对象中保存的车辆控制信息,并将新的消息标志设置为false,
267 * 表示该消息已被读取。
268 *
269 * @return 车辆控制信息。
270 */
272 _impl->_new_message = false;
273 return _impl->_control;
274 }
275 /**
276 * @brief 检查订阅者是否存活。
277 *
278 * 该函数返回内部实现对象的存活标志,用于判断订阅者是否仍然活跃。
279 *
280 * @return 如果订阅者存活,则返回true;否则返回false。
281 */
283 return _impl->_alive;
284 }
285 /**
286 * @brief 检查是否有新的消息到达。
287 *
288 * 该函数返回内部实现对象的新消息标志,用于判断是否有新的车辆控制信息到达。
289 *
290 * @return 如果有新的消息到达,则返回true;否则返回false。
291 */
293 return _impl->_new_message;
294 }
295 /**
296 * @brief 获取关联的车辆对象。
297 *
298 * 该函数返回内部实现对象中保存的车辆对象指针。
299 *
300 * @return 车辆对象指针。
301 */
303 return _impl->_vehicle;
304 }
305 /**
306 * @brief CarlaEgoVehicleControlSubscriber类的构造函数。
307 *
308 * 构造函数初始化内部实现对象,并设置相关属性,包括车辆对象指针、ROS节点名称和父节点名称。
309 *
310 * @param vehicle 车辆对象指针。
311 * @param ros_name ROS节点名称。
312 * @param parent 父节点名称。
313 */
314 CarlaEgoVehicleControlSubscriber::CarlaEgoVehicleControlSubscriber(void* vehicle, const char* ros_name, const char* parent) :
315 _impl(std::make_shared<CarlaEgoVehicleControlSubscriberImpl>()) {
316 _impl->_listener.SetOwner(this);
317 _impl->_vehicle = vehicle;
318 _name = ros_name;
319 _parent = parent;
320 }
321 /**
322 * @brief CarlaEgoVehicleControlSubscriber类的析构函数。
323 *
324 * 析构函数负责清理订阅者所使用的资源。
325 * 它首先检查_impl指针是否为空,如果不为空,则依次删除数据读取器、订阅者、主题和参与者。
326 */
328 if (!_impl)
329 return;
330
331 if (_impl->_datareader)
332 _impl->_subscriber->delete_datareader(_impl->_datareader);
333
334 if (_impl->_subscriber)
335 _impl->_participant->delete_subscriber(_impl->_subscriber);
336
337 if (_impl->_topic)
338 _impl->_participant->delete_topic(_impl->_topic);
339
340 if (_impl->_participant)
341 efd::DomainParticipantFactory::get_instance()->delete_participant(_impl->_participant);
342 }
343 /**
344 * @brief CarlaEgoVehicleControlSubscriber类的拷贝构造函数。
345 *
346 * 拷贝构造函数通过复制另一个CarlaEgoVehicleControlSubscriber对象来初始化新对象。
347 * 它复制了所有成员变量,并设置了监听器的所有者。
348 *
349 * @param other 要复制的CarlaEgoVehicleControlSubscriber对象。
350 */
352 _frame_id = other._frame_id;
353 _name = other._name;
354 _parent = other._parent;
355 _impl = other._impl;
356 _impl->_listener.SetOwner(this);
357 }
358 /**
359 * @brief 拷贝赋值运算符。
360 *
361 * 拷贝赋值运算符将当前对象替换为另一个CarlaEgoVehicleControlSubscriber对象的副本。
362 * 它复制了所有成员变量,并设置了监听器的所有者。
363 *
364 * @param other 要复制的CarlaEgoVehicleControlSubscriber对象。
365 * @return 引用当前对象。
366 */
368 _frame_id = other._frame_id;
369 _name = other._name;
370 _parent = other._parent;
371 _impl = other._impl;
372 _impl->_listener.SetOwner(this);
373
374 return *this;
375 }
376 /**
377 * @brief CarlaEgoVehicleControlSubscriber类的移动构造函数。
378 *
379 * 移动构造函数通过移动另一个CarlaEgoVehicleControlSubscriber对象的资源来初始化新对象。
380 * 它移动了所有成员变量,并设置了监听器的所有者。
381 *
382 * @param other 要移动的CarlaEgoVehicleControlSubscriber对象。
383 */
385 _frame_id = std::move(other._frame_id);
386 _name = std::move(other._name);
387 _parent = std::move(other._parent);
388 _impl = std::move(other._impl);
389 _impl->_listener.SetOwner(this);
390 }
391 /**
392 * @brief 移动赋值运算符。
393 *
394 * 移动赋值运算符将当前对象替换为通过移动另一个CarlaEgoVehicleControlSubscriber对象的资源得到的对象。
395 * 它移动了所有成员变量,并设置了监听器的所有者。
396 *
397 * @param other 要移动的CarlaEgoVehicleControlSubscriber对象。
398 * @return 引用当前对象。
399 */
401 _frame_id = std::move(other._frame_id);
402 _name = std::move(other._name);
403 _parent = std::move(other._parent);
404 _impl = std::move(other._impl);
405 _impl->_listener.SetOwner(this);
406
407 return *this;
408 }
409}
410}
CarlaEgoVehicleControlSubscriber类,用于订阅并处理来自ROS2的自动驾驶车辆控制消息
void * GetVehicle()
获取与用户关联的车辆实例的指针。
CarlaEgoVehicleControlSubscriber & operator=(const CarlaEgoVehicleControlSubscriber &)
拷贝赋值运算符,用于深拷贝赋值。
VehicleControl GetMessage()
获取最新的车辆控制消息。
CarlaEgoVehicleControlSubscriber(void *vehicle, const char *ros_name="", const char *parent="")
构造函数,初始化用户并关联到指定的车辆。
~CarlaEgoVehicleControlSubscriber()
析构函数,清理资源并销毁用户。
std::shared_ptr< CarlaEgoVehicleControlSubscriberImpl > _impl
指向内部实现结构的智能指针,用于隐藏实现细节。
bool HasNewMessage()
检查是否有新的控制消息到达。
void ForwardMessage(VehicleControl control)
(内部使用)将控制消息转发给内部处理函数。
void DestroySubscriber()
销毁用户并释放相关资源。
Carla订阅者监听器类,用于处理与ROS 2订阅者相关的事件。
const std::string & parent() const
此类表示用户在 IDL 文件中定义的类型 CarlaEgoVehicleControl 的 TopicDataType。 <>
该类表示用户在 IDL 文件中定义的结构 CarlaEgoVehicleControl。 <>
eprosima::fastrtps::types::ReturnCode_t erc
@using erc
CARLA模拟器的主命名空间。
Definition Carla.cpp:139
CarlaEgoVehicleControlSubscriber的内部实现结构体。
efd::TypeSupport _type
DDS类型支持,用于注册消息类型。
VehicleControl _control
转换为内部使用的VehicleControl结构体。
efd::DomainParticipant * _participant
DDS域参与者指针。
carla_msgs::msg::CarlaEgoVehicleControl _event
存储接收到的CARLA EgoVehicleControl消息。
CarlaSubscriberListener _listener
订阅者监听器,用于处理接收到的消息。
void * _vehicle
与车辆控制相关的指针(具体类型未在代码中定义)。