|
3 | 3 |
|
4 | 4 | #include "behaviortree_ros2/parser_utils.hpp" |
5 | 5 | #include "behaviortree_eut_plugins/utils/deserialize_json.h" |
| 6 | +#include <boost/property_tree/ptree.hpp> |
| 7 | +#include <boost/property_tree/json_parser.hpp> |
6 | 8 |
|
7 | 9 | namespace BT_ROS |
8 | 10 |
|
@@ -89,30 +91,57 @@ struct AutomaticSerialization |
89 | 91 | return ports; |
90 | 92 | } |
91 | 93 |
|
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) |
95 | 96 | { |
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 | + } |
97 | 109 |
|
| 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 | + |
98 | 114 | std::vector<uint8_t> buffer_in = RosMsgParser::BuildMessageBuffer(*(_message.get()), topic_type_); |
99 | 115 | std::string json_text; |
100 | 116 | RosMsgParser::ROS2_Deserializer deserializer_; |
101 | 117 | parser_->deserializeIntoJson(buffer_in, &json_text, &deserializer_, 0, true, true); |
102 | 118 | nlohmann::json json_parsed = nlohmann::json::parse(json_text); |
103 | | - |
| 119 | + |
104 | 120 | const auto& field_ports = fieldPorts<MessageType>({RosMsgParser::ROSType("builtin_interfaces/Time")}); |
| 121 | + |
105 | 122 | for(const auto& field_port : field_ports) |
106 | 123 | { |
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()? |
110 | 124 | 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 | + |
116 | 145 | } |
117 | 146 | } |
118 | 147 |
|
@@ -249,3 +278,4 @@ struct CustomSerialization |
249 | 278 | } // namespace BT_ROS |
250 | 279 |
|
251 | 280 | #endif |
| 281 | + |
0 commit comments