Skip to content

Commit 19e957d

Browse files
committed
bugfix on nested messages
1 parent 4a6f763 commit 19e957d

File tree

3 files changed

+103
-15
lines changed

3 files changed

+103
-15
lines changed

behaviortree_ros2/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ set(THIS_PACKAGE_DEPS
1717
generate_parameter_library
1818
rosx_introspection
1919
std_msgs
20+
geometry_msgs
2021
std_srvs
2122
geometry_msgs
2223
angles
2324
tf2
2425
tf2_geometry_msgs
2526
tf2_ros
26-
)
27+
)
2728

2829
find_package(ament_cmake REQUIRED)
2930

behaviortree_ros2/include/behaviortree_ros2/serialization_policies.hpp

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#include "behaviortree_ros2/parser_utils.hpp"
55
#include "behaviortree_eut_plugins/utils/deserialize_json.h"
6+
#include <boost/property_tree/ptree.hpp>
7+
#include <boost/property_tree/json_parser.hpp>
68

79
namespace BT_ROS
810

@@ -89,30 +91,57 @@ struct AutomaticSerialization
8991
return ports;
9092
}
9193

92-
93-
void onNewMessage(const std::shared_ptr<MessageType>& _message, BT::TreeNode& _tree_node,
94-
const std::string& _base_port_name = "")
94+
// Helper to extract nested fields "header.frame_id" [header][frame_id]
95+
nlohmann::json getNestedValue(const nlohmann::json& j, const std::string& dotted_key)
9596
{
96-
if(isMsgEmpty<MessageType>()) { return; }
97+
std::istringstream iss(dotted_key);
98+
std::string token;
99+
const nlohmann::json* current = &j;
100+
while (std::getline(iss, token, '.'))
101+
{
102+
if (!current->contains(token))
103+
throw std::runtime_error("Missing key: " + token + " in " + dotted_key);
104+
current = &((*current)[token]);
105+
}
106+
107+
return *current;
108+
}
97109

110+
void onNewMessage( const std::shared_ptr<MessageType>& _message, BT::TreeNode& _tree_node, const std::string& _base_port_name = "")
111+
{
112+
if(isMsgEmpty<MessageType>()) { return; }
113+
98114
std::vector<uint8_t> buffer_in = RosMsgParser::BuildMessageBuffer(*(_message.get()), topic_type_);
99115
std::string json_text;
100116
RosMsgParser::ROS2_Deserializer deserializer_;
101117
parser_->deserializeIntoJson(buffer_in, &json_text, &deserializer_, 0, true, true);
102118
nlohmann::json json_parsed = nlohmann::json::parse(json_text);
103-
119+
104120
const auto& field_ports = fieldPorts<MessageType>({RosMsgParser::ROSType("builtin_interfaces/Time")});
121+
105122
for(const auto& field_port : field_ports)
106123
{
107-
// Time and duration defaults to ros::Time::now and zero
108-
// TODO should we allow users to set this themselves? If so, how would they
109-
// write it? Maybe a custom convertFromString()?
110124
const auto type_id = field_port.second.type().typeID();
111-
if(type_id == RosMsgParser::TIME ||
112-
type_id == RosMsgParser::DURATION) { continue; }
113-
114-
std::string port_name = _base_port_name.empty() ? field_port.first : _base_port_name + "_" + field_port.first;
115-
BT::EutUtils::deserializeField(_tree_node, port_name, json_parsed[field_port.first]);
125+
if(type_id == RosMsgParser::TIME || type_id == RosMsgParser::DURATION)
126+
continue;
127+
128+
std::string port_name = _base_port_name.empty()
129+
? field_port.first
130+
: _base_port_name + "_" + field_port.first;
131+
132+
try
133+
{
134+
nlohmann::json value = getNestedValue(json_parsed, field_port.first);
135+
136+
BT::EutUtils::deserializeField(_tree_node, port_name, value);
137+
138+
}
139+
catch(const std::exception& e)
140+
{
141+
std::cerr << "Warning: could not deserialize field " << field_port.first
142+
<< ": " << e.what() << std::endl;
143+
}
144+
116145
}
117146
}
118147

behaviortree_ros2/src/plugin.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <std_msgs/msg/float32.hpp>
2020
#include <std_msgs/msg/float64.hpp>
2121
#include <std_msgs/msg/string.hpp>
22+
#include <geometry_msgs/msg/pose_stamped.hpp>
2223

2324
#include <std_srvs/srv/empty.hpp>
2425
#include <std_srvs/srv/set_bool.hpp>
@@ -30,11 +31,64 @@
3031
#include "btcpp_ros2_interfaces/action/execute_tree.hpp"
3132
#include "btcpp_ros2_interfaces/msg/custom_msg.hpp"
3233

34+
// Simple Action that updates an instance of Position2D in the blackboard
35+
class SayHi : public BT::StatefulActionNode
36+
{
37+
public:
38+
SayHi(const std::string& name, const BT::NodeConfig& config)
39+
: BT::StatefulActionNode(name, config)
40+
{}
41+
42+
static BT::PortsList providedPorts()
43+
{
44+
return { BT::InputPort<std::string>("person_name") };
45+
}
46+
47+
BT::NodeStatus onStart() override
48+
{
49+
const auto name = getInput<std::string>("person_name");
50+
if(!name)
51+
return BT::NodeStatus::FAILURE;
52+
53+
person_name_ = name.value();
54+
counter_ = 0;
55+
56+
std::cout << "Starting to say hi to " << person_name_ << "..." << std::endl;
57+
return BT::NodeStatus::RUNNING;
58+
}
59+
60+
BT::NodeStatus onRunning() override
61+
{
62+
if (counter_ < 3)
63+
{
64+
std::cout << "Hi " << person_name_ << "! (" << counter_+1 << "/3)" << std::endl;
65+
counter_++;
66+
return BT::NodeStatus::RUNNING;
67+
}
68+
else
69+
{
70+
std::cout << "Finished saying hi to " << person_name_ << "!" << std::endl;
71+
return BT::NodeStatus::SUCCESS;
72+
}
73+
}
74+
75+
void onHalted() override
76+
{
77+
std::cout << "SayHi halted." << std::endl;
78+
}
79+
80+
private:
81+
std::string person_name_;
82+
int counter_ = 0;
83+
};
3384

3485
using namespace BT;
3586

3687
BT_REGISTER_ROS_NODES(factory, params)
3788
{
89+
90+
factory.registerNodeType<SayHi>("SayHi");
91+
3892
//LOGS
3993
factory.registerNodeType<DebugLog>("DebugLog");
4094
factory.registerNodeType<InfoLog>("InfoLog");
@@ -62,6 +116,8 @@ BT_REGISTER_ROS_NODES(factory, params)
62116
factory.registerNodeType<AutoSerSubscriber<std_msgs::msg::Float32>>("MonitorAutoStdFloat",params);
63117
factory.registerNodeType<AutoSerSubscriber<std_msgs::msg::Float64>>("MonitorAutoStdDouble",params);
64118
factory.registerNodeType<AutoSerSubscriber<std_msgs::msg::String>>("MonitorAutoStdString",params);
119+
factory.registerNodeType<AutoSerSubscriber<geometry_msgs::msg::PoseStamped>>("MonitorAutoPoseStamped",params);
120+
factory.registerNodeType<JsonSerSubscriber<geometry_msgs::msg::PoseStamped>>("MonitorJsonPoseStamped",params);
65121

66122
// Possible variant of PRIMITIVE SUBSCRIBER WITH JSON Serialization
67123
factory.registerNodeType<JsonSerSubscriber<std_msgs::msg::Int32>>("MonitorJsonStdInt",params);
@@ -80,7 +136,8 @@ BT_REGISTER_ROS_NODES(factory, params)
80136
factory.registerNodeType<AutoDesPublisher<std_msgs::msg::Float32>>("PublishAutoStdFloat",params);
81137
factory.registerNodeType<AutoDesPublisher<std_msgs::msg::Float64>>("PublishAutoStdDouble",params);
82138
factory.registerNodeType<AutoDesPublisher<std_msgs::msg::String>>("PublishAutoStdString",params);
83-
139+
factory.registerNodeType<AutoDesPublisher<geometry_msgs::msg::PoseStamped>>("PublishAutoPoseStamped",params);
140+
84141
//PRIMITIVE SERVICES
85142
factory.registerNodeType<AutoDesJsonSerServiceClient<std_srvs::srv::Empty>>("ServiceAutoCallJsonEmpty",params);
86143
factory.registerNodeType<AutoDesJsonSerServiceClient<std_srvs::srv::SetBool>>("ServiceAutoCallJsonBool",params);
@@ -97,4 +154,5 @@ BT_REGISTER_ROS_NODES(factory, params)
97154
factory.registerNodeType<SmartJsonSerSubscriber<btcpp_ros2_interfaces::msg::NodeStatus>>("MonitorSmartJsonNodeStatus",params);
98155
factory.registerNodeType<SmartJsonSerSubscriber<btcpp_ros2_interfaces::msg::CustomMsg>>("MonitorSmartJsonCustomMsg",params);
99156

157+
100158
};

0 commit comments

Comments
 (0)