136 const rclcpp::QoS qos_;
137 std::
string topic_name_;
138 bool topic_name_should_be_checked_ = false;
139 std::shared_ptr<SubscriberInstance> sub_instance_;
140 std::shared_ptr<MessageT> last_msg_;
141 boost::signals2::connection signal_connection_;
142 std::
string subscriber_key_;
144 bool createSubscriber(const std::
string& topic_name);
151template <class MessageT>
152inline
RosSubscriberNode<MessageT>::SubscriberInstance::SubscriberInstance(std::shared_ptr<rclcpp::Node> node,
153 const std::
string& topic_name,
154 const rclcpp::QoS& qos)
157 callback_group = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive,
false);
158 callback_group_executor.add_callback_group(callback_group, node->get_node_base_interface());
160 rclcpp::SubscriptionOptions option;
161 option.callback_group = callback_group;
164 auto callback = [
this](
const std::shared_ptr<MessageT> msg) {
168 subscriber = node->create_subscription<MessageT>(topic_name, qos, callback, option);
171template <
class MessageT>
173 const Context& context,
const rclcpp::QoS& qos)
174 : BT::ConditionNode{ instance_name, config },
logger_(context.getLogger()), context_{ context }, qos_{ qos }
177 auto portIt = config.input_ports.find(
"topic_name");
178 if (portIt != config.input_ports.end())
180 const std::string& bb_topic_name = portIt->second;
182 if (isBlackboardPointer(bb_topic_name))
185 topic_name_should_be_checked_ = true;
187 else if (!bb_topic_name.empty())
190 createSubscriber(bb_topic_name);
196 createSubscriber(context.default_port_name);
200template <
class MessageT>
201inline bool RosSubscriberNode<MessageT>::createSubscriber(
const std::string& topic_name)
203 if (topic_name.empty())
205 throw exceptions::RosNodeError(getFullName() +
" - Argument topic_name is empty when trying to create a client.");
209 throw exceptions::RosNodeError(getFullName() +
" - Cannot call createSubscriber() more than once.");
213 std::unique_lock lk(registryMutex());
215 auto node = getRosContext().nh.lock();
218 throw exceptions::RosNodeError(getFullName() +
219 " - The shared pointer to the ROS node went out of scope. The tree node doesn't "
220 "take the ownership of the node.");
222 subscriber_key_ = std::string(node->get_fully_qualified_name()) +
"/" + topic_name;
224 auto& registry = getRegistry();
225 auto it = registry.find(subscriber_key_);
226 if (it == registry.end() || it->second.expired())
228 sub_instance_ = std::make_shared<SubscriberInstance>(node, topic_name, qos_);
229 registry.insert({ subscriber_key_, sub_instance_ });
230 RCLCPP_DEBUG(logger_,
"%s - Created subscriber for topic '%s'.", getFullName().c_str(), topic_name.c_str());
234 sub_instance_ = it->second.lock();
238 if (sub_instance_->last_msg)
240 last_msg_ = sub_instance_->last_msg;
245 sub_instance_->broadcaster.connect([
this](
const std::shared_ptr<MessageT> msg) { last_msg_ = msg; });
247 topic_name_ = topic_name;
251template <
class MessageT>
257 if (!sub_instance_ || (status() == BT::NodeStatus::IDLE && topic_name_should_be_checked_))
259 std::string topic_name;
260 getInput(
"topic_name", topic_name);
261 if (topic_name_ != topic_name)
263 createSubscriber(topic_name);
270 " - You must specify a service name either by using a default value or by "
271 "passing a value to the corresponding dynamic input port.");
274 auto check_status = [
this](BT::NodeStatus status) {
275 if (!isStatusCompleted(status))
281 sub_instance_->callback_group_executor.spin_some();
282 auto status = check_status(onTick(last_msg_));
287template <
class MessageT>
291 return BT::NodeStatus::FAILURE;
292 return onMessageReceived(*last_msg_ptr);
295template <
class MessageT>
298 return BT::NodeStatus::SUCCESS;
301template <
class MessageT>
306 if (registrationName().empty())
308 if (this->name() == this->registrationName())
310 return this->name() +
" (Type: " + this->registrationName() +
")";
313template <
class MessageT>
319template <
class MessageT>
322 static std::mutex sub_mutex;
326template <
class MessageT>
329 static SubscribersRegistry subscribers_registry;
330 return subscribers_registry;