17#include "auto_apms_behavior_tree/util/parameter.hpp"
18#include "auto_apms_behavior_tree_core/node.hpp"
19#include "rcl_interfaces/msg/parameter.hpp"
20#include "rcl_interfaces/msg/parameter_type.hpp"
21#include "rcl_interfaces/msg/parameter_value.hpp"
22#include "rcl_interfaces/srv/set_parameters.hpp"
24#define INPUT_KEY_PARAM_NAME "parameter"
25#define INPUT_KEY_PARAM_VALUE "value"
26#define INPUT_KEY_NODE_NAME "node"
35 SetParameterTemplate(
const std::string & instance_name,
const Config & config,
const Context & context)
39 std::string node_name = context_.getFullyQualifiedRosNodeName();
41 config.input_ports.find(INPUT_KEY_NODE_NAME) != config.input_ports.end() &&
42 !config.input_ports.at(INPUT_KEY_NODE_NAME).empty()) {
43 node_name = config.input_ports.at(INPUT_KEY_NODE_NAME);
48 static BT::PortsList providedPorts()
55 using AnyType =
typename std::conditional_t<std::is_same_v<BT::Any, T>, BT::AnyTypeAllowed, T>;
57 BT::InputPort<std::string>(
58 INPUT_KEY_NODE_NAME,
"Name of the targeted ROS 2 node. Leave empty to target this executor's node."),
59 BT::InputPort<AnyType>(INPUT_KEY_PARAM_VALUE,
"Value of the parameter to be set."),
60 BT::InputPort<std::string>(INPUT_KEY_PARAM_NAME,
"Name of the parameter to be set."),
64 bool setRequest(Request::SharedPtr & request)
override final
66 rcl_interfaces::msg::Parameter parameter;
67 const BT::Expected<std::string> expected_name = getInput<std::string>(INPUT_KEY_PARAM_NAME);
68 if (!expected_name || expected_name.value().empty()) {
70 logger_,
"%s - Parameter name must not be empty.", context_.getFullyQualifiedTreeNodeName(
this).c_str());
71 RCLCPP_DEBUG_EXPRESSION(
72 logger_, !expected_name,
"%s - Error message: %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(),
73 expected_name.error().c_str());
76 parameter.name = expected_name.value();
78 rclcpp::ParameterType inferred_param_type = rclcpp::PARAMETER_NOT_SET;
79 if constexpr (!std::is_same_v<BT::Any, T>) {
80 inferred_param_type = rclcpp::ParameterValue(T()).get_type();
83 rcl_interfaces::msg::ParameterValue param_val;
84 const BT::PortsRemapping::iterator it = config().input_ports.find(INPUT_KEY_PARAM_VALUE);
85 if (it == config().input_ports.end() || it->second.empty()) {
86 if constexpr (std::is_same_v<BT::Any, T>) {
87 throw exceptions::RosNodeError(
88 context_.getFullyQualifiedTreeNodeName(
this) +
" - Parameter value must not be empty.");
91 param_val.type = inferred_param_type;
96 if (!isBlackboardPointer(it->second) && std::is_same_v<BT::Any, T>) {
97 throw exceptions::RosNodeError(
98 context_.getFullyQualifiedTreeNodeName(
this) +
99 " - Cannot infer type from literal string. Use one of the type specialized versions of SetParameter "
103 const BT::Expected<T> expected_entry = getInput<T>(INPUT_KEY_PARAM_VALUE);
104 if (!expected_entry) {
106 logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected_entry.error().c_str());
109 const BT::Expected<rclcpp::ParameterValue> expected_param_val =
111 if (!expected_param_val) {
114 logger_,
"%s - %s", context_.getFullyQualifiedTreeNodeName(
this).c_str(), expected_param_val.error().c_str());
117 param_val = expected_param_val.value().to_value_msg();
120 parameter.value = param_val;
121 requested_parameter_ = rclcpp::Parameter(parameter.name, parameter.value);
122 request->parameters.push_back(parameter);
126 BT::NodeStatus onResponseReceived(
const Response::SharedPtr & response)
override final
128 const rcl_interfaces::msg::SetParametersResult & result = response->results[0];
129 if (!result.successful) {
131 logger_,
"Failed to set parameter %s = %s (Type: %s) via service '%s': %s",
132 requested_parameter_.get_name().c_str(), requested_parameter_.value_to_string().c_str(),
133 requested_parameter_.get_type_name().c_str(),
getServiceName().c_str(), result.reason.c_str());
134 return BT::NodeStatus::FAILURE;
136 return BT::NodeStatus::SUCCESS;
140 rclcpp::Parameter requested_parameter_;
144class SetParameter :
public SetParameterTemplate<BT::Any>
147 using SetParameterTemplate::SetParameterTemplate;
150class SetParameterBool :
public SetParameterTemplate<bool>
153 using SetParameterTemplate::SetParameterTemplate;
156class SetParameterInt :
public SetParameterTemplate<int64_t>
159 using SetParameterTemplate::SetParameterTemplate;
162class SetParameterDouble :
public SetParameterTemplate<double>
165 using SetParameterTemplate::SetParameterTemplate;
168class SetParameterString :
public SetParameterTemplate<std::string>
171 using SetParameterTemplate::SetParameterTemplate;
174class SetParameterByteVec :
public SetParameterTemplate<std::vector<uint8_t>>
177 using SetParameterTemplate::SetParameterTemplate;
180class SetParameterBoolVec :
public SetParameterTemplate<std::vector<bool>>
183 using SetParameterTemplate::SetParameterTemplate;
186class SetParameterIntVec :
public SetParameterTemplate<std::vector<int64_t>>
189 using SetParameterTemplate::SetParameterTemplate;
192class SetParameterDoubleVec :
public SetParameterTemplate<std::vector<double>>
195 using SetParameterTemplate::SetParameterTemplate;
198class SetParameterStringVec :
public SetParameterTemplate<std::vector<std::string>>
201 using SetParameterTemplate::SetParameterTemplate;
Generic behavior tree node wrapper for a ROS 2 service client.
std::string getServiceName() const
bool createClient(const std::string &service_name)
RosServiceNode(const std::string &instance_name, const Config &config, Context context)
#define AUTO_APMS_BEHAVIOR_TREE_REGISTER_NODE(type)
Macro for registering a behavior tree node plugin.
Powerful tooling for incorporating behavior trees for task development.
BT::Expected< rclcpp::ParameterValue > createParameterValueFromAny(const BT::Any &any, rclcpp::ParameterType type)
Convert a BT::Any object to a ROS 2 parameter value.