Skip to content

Commit 374edcf

Browse files
committed
Fix issue #58: use weak_ptr to avoid circular shared_ptr ownership
1 parent 784d4e9 commit 374edcf

File tree

6 files changed

+58
-24
lines changed

6 files changed

+58
-24
lines changed

behaviortree_ros2/include/behaviortree_ros2/bt_action_node.hpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,20 @@ class RosActionNode : public BT::ActionNodeBase
188188

189189
rclcpp::Logger logger()
190190
{
191-
return node_->get_logger();
191+
if(auto node = node_.lock())
192+
{
193+
return node->get_logger();
194+
}
195+
return rclcpp::get_logger("RosActionNode");
196+
}
197+
198+
rclcpp::Time now()
199+
{
200+
if(auto node = node_.lock())
201+
{
202+
return node->now();
203+
}
204+
return rclcpp::Clock(RCL_ROS_TIME).now();
192205
}
193206

194207
using ClientsRegistry =
@@ -200,7 +213,7 @@ class RosActionNode : public BT::ActionNodeBase
200213
return action_clients_registry;
201214
}
202215

203-
std::shared_ptr<rclcpp::Node> node_;
216+
std::weak_ptr<rclcpp::Node> node_;
204217
std::shared_ptr<ActionClientInstance> client_instance_;
205218
std::string action_name_;
206219
bool action_name_may_change_ = false;
@@ -302,13 +315,14 @@ inline bool RosActionNode<T>::createClient(const std::string& action_name)
302315
}
303316

304317
std::unique_lock lk(getMutex());
305-
action_client_key_ = std::string(node_->get_fully_qualified_name()) + "/" + action_name;
318+
auto node = node_.lock();
319+
action_client_key_ = std::string(node->get_fully_qualified_name()) + "/" + action_name;
306320

307321
auto& registry = getRegistry();
308322
auto it = registry.find(action_client_key_);
309323
if(it == registry.end() || it->second.expired())
310324
{
311-
client_instance_ = std::make_shared<ActionClientInstance>(node_, action_name);
325+
client_instance_ = std::make_shared<ActionClientInstance>(node, action_name);
312326
registry.insert({ action_client_key_, client_instance_ });
313327
}
314328
else
@@ -421,7 +435,7 @@ inline NodeStatus RosActionNode<T>::tick()
421435
}
422436

423437
future_goal_handle_ = action_client->async_send_goal(goal, goal_options);
424-
time_goal_sent_ = node_->now();
438+
time_goal_sent_ = now();
425439

426440
return NodeStatus::RUNNING;
427441
}
@@ -442,7 +456,7 @@ inline NodeStatus RosActionNode<T>::tick()
442456
future_goal_handle_, nodelay);
443457
if(ret != rclcpp::FutureReturnCode::SUCCESS)
444458
{
445-
if((node_->now() - time_goal_sent_) > timeout)
459+
if((now() - time_goal_sent_) > timeout)
446460
{
447461
return CheckStatus(onFailure(SEND_GOAL_TIMEOUT));
448462
}

behaviortree_ros2/include/behaviortree_ros2/bt_service_node.hpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,20 @@ class RosServiceNode : public BT::ActionNodeBase
159159

160160
rclcpp::Logger logger()
161161
{
162-
return node_->get_logger();
162+
if(auto node = node_.lock())
163+
{
164+
return node->get_logger();
165+
}
166+
return rclcpp::get_logger("RosServiceNode");
167+
}
168+
169+
rclcpp::Time now()
170+
{
171+
if(auto node = node_.lock())
172+
{
173+
return node->now();
174+
}
175+
return rclcpp::Clock(RCL_ROS_TIME).now();
163176
}
164177

165178
using ClientsRegistry =
@@ -171,7 +184,7 @@ class RosServiceNode : public BT::ActionNodeBase
171184
return clients_registry;
172185
}
173186

174-
std::shared_ptr<rclcpp::Node> node_;
187+
std::weak_ptr<rclcpp::Node> node_;
175188
std::string service_name_;
176189
bool service_name_may_change_ = false;
177190
const std::chrono::milliseconds service_timeout_;
@@ -268,13 +281,14 @@ inline bool RosServiceNode<T>::createClient(const std::string& service_name)
268281
}
269282

270283
std::unique_lock lk(getMutex());
271-
auto client_key = std::string(node_->get_fully_qualified_name()) + "/" + service_name;
284+
auto node = node_.lock();
285+
auto client_key = std::string(node->get_fully_qualified_name()) + "/" + service_name;
272286

273287
auto& registry = getRegistry();
274288
auto it = registry.find(client_key);
275289
if(it == registry.end() || it->second.expired())
276290
{
277-
srv_instance_ = std::make_shared<ServiceClientInstance>(node_, service_name);
291+
srv_instance_ = std::make_shared<ServiceClientInstance>(node, service_name);
278292
registry.insert({ client_key, srv_instance_ });
279293

280294
RCLCPP_INFO(logger(), "Node [%s] created service client [%s]", name().c_str(),
@@ -289,8 +303,8 @@ inline bool RosServiceNode<T>::createClient(const std::string& service_name)
289303
bool found = srv_instance_->service_client->wait_for_service(wait_for_service_timeout_);
290304
if(!found)
291305
{
292-
RCLCPP_ERROR(node_->get_logger(), "%s: Service with name '%s' is not reachable.",
293-
name().c_str(), service_name_.c_str());
306+
RCLCPP_ERROR(logger(), "%s: Service with name '%s' is not reachable.", name().c_str(),
307+
service_name_.c_str());
294308
}
295309
return found;
296310
}
@@ -350,7 +364,7 @@ inline NodeStatus RosServiceNode<T>::tick()
350364
}
351365

352366
future_response_ = srv_instance_->service_client->async_send_request(request).share();
353-
time_request_sent_ = node_->now();
367+
time_request_sent_ = now();
354368

355369
return NodeStatus::RUNNING;
356370
}
@@ -371,7 +385,7 @@ inline NodeStatus RosServiceNode<T>::tick()
371385

372386
if(ret != rclcpp::FutureReturnCode::SUCCESS)
373387
{
374-
if((node_->now() - time_request_sent_) > timeout)
388+
if((now() - time_request_sent_) > timeout)
375389
{
376390
return CheckStatus(onFailure(SERVICE_TIMEOUT));
377391
}

behaviortree_ros2/include/behaviortree_ros2/bt_topic_pub_node.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class RosTopicPubNode : public BT::ConditionNode
3939
/** You are not supposed to instantiate this class directly, the factory will do it.
4040
* To register this class into the factory, use:
4141
*
42-
* RegisterRosAction<DerivedClasss>(factory, params)
42+
* RegisterRosAction<DerivedClass>(factory, params)
4343
*
4444
* Note that if the external_action_client is not set, the constructor will build its own.
4545
* */

behaviortree_ros2/include/behaviortree_ros2/bt_topic_sub_node.hpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class RosTopicSubNode : public BT::ConditionNode
7676
return subscribers_registry;
7777
}
7878

79-
std::shared_ptr<rclcpp::Node> node_;
79+
std::weak_ptr<rclcpp::Node> node_;
8080
std::shared_ptr<SubscriberInstance> sub_instance_;
8181
std::shared_ptr<TopicT> last_msg_;
8282
std::string topic_name_;
@@ -85,7 +85,11 @@ class RosTopicSubNode : public BT::ConditionNode
8585

8686
rclcpp::Logger logger()
8787
{
88-
return node_->get_logger();
88+
if(auto node = node_.lock())
89+
{
90+
return node->get_logger();
91+
}
92+
return rclcpp::get_logger("RosTopicSubNode");
8993
}
9094

9195
public:
@@ -244,13 +248,16 @@ inline bool RosTopicSubNode<T>::createSubscriber(const std::string& topic_name)
244248

245249
// find SubscriberInstance in the registry
246250
std::unique_lock lk(registryMutex());
247-
subscriber_key_ = std::string(node_->get_fully_qualified_name()) + "/" + topic_name;
251+
252+
auto shared_node = node_.lock();
253+
subscriber_key_ =
254+
std::string(shared_node->get_fully_qualified_name()) + "/" + topic_name;
248255

249256
auto& registry = getRegistry();
250257
auto it = registry.find(subscriber_key_);
251258
if(it == registry.end() || it->second.expired())
252259
{
253-
sub_instance_ = std::make_shared<SubscriberInstance>(node_, topic_name);
260+
sub_instance_ = std::make_shared<SubscriberInstance>(shared_node, topic_name);
254261
registry.insert({ subscriber_key_, sub_instance_ });
255262

256263
RCLCPP_INFO(logger(), "Node [%s] created Subscriber to topic [%s]", name().c_str(),

behaviortree_ros2/include/behaviortree_ros2/ros_node_params.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ namespace BT
2424

2525
struct RosNodeParams
2626
{
27-
std::shared_ptr<rclcpp::Node> nh;
27+
std::weak_ptr<rclcpp::Node> nh;
2828

2929
// This has different meaning based on the context:
3030
//

btcpp_ros2_samples/src/sleep_action.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,21 @@ bool SleepAction::setGoal(RosActionNode::Goal& goal)
1010

1111
NodeStatus SleepAction::onResultReceived(const RosActionNode::WrappedResult& wr)
1212
{
13-
RCLCPP_INFO(node_->get_logger(), "%s: onResultReceived. Done = %s", name().c_str(),
13+
RCLCPP_INFO(logger(), "%s: onResultReceived. Done = %s", name().c_str(),
1414
wr.result->done ? "true" : "false");
1515

1616
return wr.result->done ? NodeStatus::SUCCESS : NodeStatus::FAILURE;
1717
}
1818

1919
NodeStatus SleepAction::onFailure(ActionNodeErrorCode error)
2020
{
21-
RCLCPP_ERROR(node_->get_logger(), "%s: onFailure with error: %s", name().c_str(),
22-
toStr(error));
21+
RCLCPP_ERROR(logger(), "%s: onFailure with error: %s", name().c_str(), toStr(error));
2322
return NodeStatus::FAILURE;
2423
}
2524

2625
void SleepAction::onHalt()
2726
{
28-
RCLCPP_INFO(node_->get_logger(), "%s: onHalt", name().c_str());
27+
RCLCPP_INFO(logger(), "%s: onHalt", name().c_str());
2928
}
3029

3130
// Plugin registration.

0 commit comments

Comments
 (0)