ros2_control - jazzy
Loading...
Searching...
No Matches
joint_limits_rosparam.hpp
1// Copyright 2020 PAL Robotics S.L.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
17#ifndef JOINT_LIMITS__JOINT_LIMITS_ROSPARAM_HPP_
18#define JOINT_LIMITS__JOINT_LIMITS_ROSPARAM_HPP_
19
20#include <fmt/compile.h>
21
22#include <limits>
23#include <string>
24#include <vector>
25
26#include "joint_limits/joint_limits.hpp"
27#include "rclcpp/node.hpp"
28#include "rclcpp_lifecycle/lifecycle_node.hpp"
29
30namespace // utilities
31{
33
39template <typename ParameterT>
40auto auto_declare(
41 const rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & param_itf,
42 const std::string & name, const ParameterT & default_value)
43{
44 if (!param_itf->has_parameter(name))
45 {
46 auto param_default_value = rclcpp::ParameterValue(default_value);
47 param_itf->declare_parameter(name, param_default_value);
48 }
49 return param_itf->get_parameter(name).get_value<ParameterT>();
50}
51} // namespace
52
53namespace joint_limits
54{
89 const std::string & joint_name,
90 const rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & param_itf,
91 const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr & logging_itf)
92{
93 const std::string param_base_name = fmt::format(FMT_COMPILE("joint_limits.{}"), joint_name);
94 try
95 {
96 auto_declare<bool>(param_itf, param_base_name + ".has_position_limits", false);
97 auto_declare<double>(
98 param_itf, param_base_name + ".min_position", std::numeric_limits<double>::quiet_NaN());
99 auto_declare<double>(
100 param_itf, param_base_name + ".max_position", std::numeric_limits<double>::quiet_NaN());
101 auto_declare<bool>(param_itf, param_base_name + ".has_velocity_limits", false);
102 auto_declare<double>(
103 param_itf, param_base_name + ".max_velocity", std::numeric_limits<double>::quiet_NaN());
104 auto_declare<bool>(param_itf, param_base_name + ".has_acceleration_limits", false);
105 auto_declare<double>(
106 param_itf, param_base_name + ".max_acceleration", std::numeric_limits<double>::quiet_NaN());
107 auto_declare<bool>(param_itf, param_base_name + ".has_deceleration_limits", false);
108 auto_declare<double>(
109 param_itf, param_base_name + ".max_deceleration", std::numeric_limits<double>::quiet_NaN());
110 auto_declare<bool>(param_itf, param_base_name + ".has_jerk_limits", false);
111 auto_declare<double>(
112 param_itf, param_base_name + ".max_jerk", std::numeric_limits<double>::quiet_NaN());
113 auto_declare<bool>(param_itf, param_base_name + ".has_effort_limits", false);
114 auto_declare<double>(
115 param_itf, param_base_name + ".max_effort", std::numeric_limits<double>::quiet_NaN());
116 auto_declare<bool>(param_itf, param_base_name + ".angle_wraparound", false);
117 auto_declare<bool>(param_itf, param_base_name + ".has_soft_limits", false);
118 auto_declare<double>(
119 param_itf, param_base_name + ".k_position", std::numeric_limits<double>::quiet_NaN());
120 auto_declare<double>(
121 param_itf, param_base_name + ".k_velocity", std::numeric_limits<double>::quiet_NaN());
122 auto_declare<double>(
123 param_itf, param_base_name + ".soft_lower_limit", std::numeric_limits<double>::quiet_NaN());
124 auto_declare<double>(
125 param_itf, param_base_name + ".soft_upper_limit", std::numeric_limits<double>::quiet_NaN());
126 }
127 catch (const std::exception & ex)
128 {
129 RCLCPP_ERROR(logging_itf->get_logger(), "%s", ex.what());
130 return false;
131 }
132 return true;
133}
134
146inline bool declare_parameters(const std::string & joint_name, const rclcpp::Node::SharedPtr & node)
147{
148 return declare_parameters(
149 joint_name, node->get_node_parameters_interface(), node->get_node_logging_interface());
150}
151
163 const std::string & joint_name, const rclcpp_lifecycle::LifecycleNode::SharedPtr & lifecycle_node)
164{
165 return declare_parameters(
166 joint_name, lifecycle_node->get_node_parameters_interface(),
167 lifecycle_node->get_node_logging_interface());
168}
169
171
228 const std::string & joint_name,
229 const rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & param_itf,
230 const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr & logging_itf,
231 JointLimits & limits)
232{
233 const std::string param_base_name = fmt::format(FMT_COMPILE("joint_limits.{}"), joint_name);
234 try
235 {
236 if (
237 !param_itf->has_parameter(param_base_name + ".has_position_limits") &&
238 !param_itf->has_parameter(param_base_name + ".min_position") &&
239 !param_itf->has_parameter(param_base_name + ".max_position") &&
240 !param_itf->has_parameter(param_base_name + ".has_velocity_limits") &&
241 !param_itf->has_parameter(param_base_name + ".max_velocity") &&
242 !param_itf->has_parameter(param_base_name + ".has_acceleration_limits") &&
243 !param_itf->has_parameter(param_base_name + ".max_acceleration") &&
244 !param_itf->has_parameter(param_base_name + ".has_deceleration_limits") &&
245 !param_itf->has_parameter(param_base_name + ".max_deceleration") &&
246 !param_itf->has_parameter(param_base_name + ".has_jerk_limits") &&
247 !param_itf->has_parameter(param_base_name + ".max_jerk") &&
248 !param_itf->has_parameter(param_base_name + ".has_effort_limits") &&
249 !param_itf->has_parameter(param_base_name + ".max_effort") &&
250 !param_itf->has_parameter(param_base_name + ".angle_wraparound"))
251 {
252 RCLCPP_ERROR(
253 logging_itf->get_logger(),
254 "No joint limits specification found for joint '%s' in the parameter server "
255 "(param name: %s).",
256 joint_name.c_str(), param_base_name.c_str());
257 return false;
258 }
259 }
260 catch (const std::exception & ex)
261 {
262 RCLCPP_ERROR(logging_itf->get_logger(), "%s", ex.what());
263 return false;
264 }
265
266 // Position limits
267 if (param_itf->has_parameter(param_base_name + ".has_position_limits"))
268 {
269 limits.has_position_limits =
270 param_itf->get_parameter(param_base_name + ".has_position_limits").as_bool();
271 if (
272 limits.has_position_limits && param_itf->has_parameter(param_base_name + ".min_position") &&
273 param_itf->has_parameter(param_base_name + ".max_position"))
274 {
275 limits.min_position = param_itf->get_parameter(param_base_name + ".min_position").as_double();
276 limits.max_position = param_itf->get_parameter(param_base_name + ".max_position").as_double();
277 }
278 else
279 {
280 limits.has_position_limits = false;
281 }
282
283 if (
284 !limits.has_position_limits &&
285 param_itf->has_parameter(param_base_name + ".angle_wraparound"))
286 {
287 limits.angle_wraparound =
288 param_itf->get_parameter(param_base_name + ".angle_wraparound").as_bool();
289 }
290 }
291
292 // Velocity limits
293 if (param_itf->has_parameter(param_base_name + ".has_velocity_limits"))
294 {
295 limits.has_velocity_limits =
296 param_itf->get_parameter(param_base_name + ".has_velocity_limits").as_bool();
297 if (limits.has_velocity_limits && param_itf->has_parameter(param_base_name + ".max_velocity"))
298 {
299 limits.max_velocity = param_itf->get_parameter(param_base_name + ".max_velocity").as_double();
300 }
301 else
302 {
303 limits.has_velocity_limits = false;
304 }
305 }
306
307 // Acceleration limits
308 if (param_itf->has_parameter(param_base_name + ".has_acceleration_limits"))
309 {
310 limits.has_acceleration_limits =
311 param_itf->get_parameter(param_base_name + ".has_acceleration_limits").as_bool();
312 if (
313 limits.has_acceleration_limits &&
314 param_itf->has_parameter(param_base_name + ".max_acceleration"))
315 {
316 limits.max_acceleration =
317 param_itf->get_parameter(param_base_name + ".max_acceleration").as_double();
318 }
319 else
320 {
321 limits.has_acceleration_limits = false;
322 }
323 }
324
325 // Deceleration limits
326 if (param_itf->has_parameter(param_base_name + ".has_deceleration_limits"))
327 {
328 limits.has_deceleration_limits =
329 param_itf->get_parameter(param_base_name + ".has_deceleration_limits").as_bool();
330 if (
331 limits.has_deceleration_limits &&
332 param_itf->has_parameter(param_base_name + ".max_deceleration"))
333 {
334 limits.max_deceleration =
335 param_itf->get_parameter(param_base_name + ".max_deceleration").as_double();
336 }
337 else
338 {
339 limits.has_deceleration_limits = false;
340 }
341 }
342
343 // Jerk limits
344 if (param_itf->has_parameter(param_base_name + ".has_jerk_limits"))
345 {
346 limits.has_jerk_limits =
347 param_itf->get_parameter(param_base_name + ".has_jerk_limits").as_bool();
348 if (limits.has_jerk_limits && param_itf->has_parameter(param_base_name + ".max_jerk"))
349 {
350 limits.max_jerk = param_itf->get_parameter(param_base_name + ".max_jerk").as_double();
351 }
352 else
353 {
354 limits.has_jerk_limits = false;
355 }
356 }
357
358 // Effort limits
359 if (param_itf->has_parameter(param_base_name + ".has_effort_limits"))
360 {
361 limits.has_effort_limits =
362 param_itf->get_parameter(param_base_name + ".has_effort_limits").as_bool();
363 if (limits.has_effort_limits && param_itf->has_parameter(param_base_name + ".max_effort"))
364 {
365 limits.has_effort_limits = true;
366 limits.max_effort = param_itf->get_parameter(param_base_name + ".max_effort").as_double();
367 }
368 else
369 {
370 limits.has_effort_limits = false;
371 }
372 }
373
374 return true;
375}
376
391 const std::string & joint_name, const rclcpp::Node::SharedPtr & node, JointLimits & limits)
392{
393 return get_joint_limits(
394 joint_name, node->get_node_parameters_interface(), node->get_node_logging_interface(), limits);
395}
396
411 const std::string & joint_name, const rclcpp_lifecycle::LifecycleNode::SharedPtr & lifecycle_node,
412 JointLimits & limits)
413{
414 return get_joint_limits(
415 joint_name, lifecycle_node->get_node_parameters_interface(),
416 lifecycle_node->get_node_logging_interface(), limits);
417}
418
434 const std::string & joint_name, const std::vector<rclcpp::Parameter> & parameters,
435 const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr & logging_itf,
436 JointLimits & updated_limits)
437{
438 const std::string param_base_name = fmt::format(FMT_COMPILE("joint_limits.{}"), joint_name);
439 bool changed = false;
440
441 // update first numerical values to make later checks for "has" limits members
442 for (auto & parameter : parameters)
443 {
444 const std::string param_name = parameter.get_name();
445 try
446 {
447 if (param_name == param_base_name + ".min_position")
448 {
449 changed = updated_limits.min_position != parameter.get_value<double>();
450 updated_limits.min_position = parameter.get_value<double>();
451 }
452 else if (param_name == param_base_name + ".max_position")
453 {
454 changed = updated_limits.max_position != parameter.get_value<double>();
455 updated_limits.max_position = parameter.get_value<double>();
456 }
457 else if (param_name == param_base_name + ".max_velocity")
458 {
459 changed = updated_limits.max_velocity != parameter.get_value<double>();
460 updated_limits.max_velocity = parameter.get_value<double>();
461 }
462 else if (param_name == param_base_name + ".max_acceleration")
463 {
464 changed = updated_limits.max_acceleration != parameter.get_value<double>();
465 updated_limits.max_acceleration = parameter.get_value<double>();
466 }
467 else if (param_name == param_base_name + ".max_deceleration")
468 {
469 changed = updated_limits.max_deceleration != parameter.get_value<double>();
470 updated_limits.max_deceleration = parameter.get_value<double>();
471 }
472 else if (param_name == param_base_name + ".max_jerk")
473 {
474 changed = updated_limits.max_jerk != parameter.get_value<double>();
475 updated_limits.max_jerk = parameter.get_value<double>();
476 }
477 else if (param_name == param_base_name + ".max_effort")
478 {
479 changed = updated_limits.max_effort != parameter.get_value<double>();
480 updated_limits.max_effort = parameter.get_value<double>();
481 }
482 }
483 catch (const rclcpp::exceptions::InvalidParameterTypeException & e)
484 {
485 RCLCPP_WARN(logging_itf->get_logger(), "Please use the right type: %s", e.what());
486 }
487 }
488
489 for (auto & parameter : parameters)
490 {
491 const std::string param_name = parameter.get_name();
492 try
493 {
494 if (param_name == param_base_name + ".has_position_limits")
495 {
496 updated_limits.has_position_limits = parameter.get_value<bool>();
497 if (updated_limits.has_position_limits)
498 {
499 if (std::isnan(updated_limits.min_position) || std::isnan(updated_limits.max_position))
500 {
501 RCLCPP_WARN(
502 logging_itf->get_logger(),
503 "PARAMETER NOT UPDATED: Position limits can not be used, i.e., "
504 "'has_position_limits' flag can not be set, if 'min_position' "
505 "and 'max_position' are not set or not have valid double values.");
506 updated_limits.has_position_limits = false;
507 }
508 else if (updated_limits.min_position >= updated_limits.max_position)
509 {
510 RCLCPP_WARN(
511 logging_itf->get_logger(),
512 "PARAMETER NOT UPDATED: Position limits can not be used, i.e., "
513 "'has_position_limits' flag can not be set, if not "
514 "'min_position' < 'max_position'");
515 updated_limits.has_position_limits = false;
516 }
517 else
518 {
519 changed = true;
520 }
521 }
522 }
523 else if (param_name == param_base_name + ".has_velocity_limits")
524 {
525 updated_limits.has_velocity_limits = parameter.get_value<bool>();
526 if (updated_limits.has_velocity_limits && std::isnan(updated_limits.max_velocity))
527 {
528 RCLCPP_WARN(
529 logging_itf->get_logger(),
530 "PARAMETER NOT UPDATED: 'has_velocity_limits' flag can not be set if 'min_velocity' "
531 "and 'max_velocity' are not set or not have valid double values.");
532 updated_limits.has_velocity_limits = false;
533 }
534 else
535 {
536 changed = true;
537 }
538 }
539 else if (param_name == param_base_name + ".has_acceleration_limits")
540 {
541 updated_limits.has_acceleration_limits = parameter.get_value<bool>();
542 if (updated_limits.has_acceleration_limits && std::isnan(updated_limits.max_acceleration))
543 {
544 RCLCPP_WARN(
545 logging_itf->get_logger(),
546 "PARAMETER NOT UPDATED: 'has_acceleration_limits' flag can not be set if "
547 "'max_acceleration' is not set or not have valid double values.");
548 updated_limits.has_acceleration_limits = false;
549 }
550 else
551 {
552 changed = true;
553 }
554 }
555 else if (param_name == param_base_name + ".has_deceleration_limits")
556 {
557 updated_limits.has_deceleration_limits = parameter.get_value<bool>();
558 if (updated_limits.has_deceleration_limits && std::isnan(updated_limits.max_deceleration))
559 {
560 RCLCPP_WARN(
561 logging_itf->get_logger(),
562 "PARAMETER NOT UPDATED: 'has_deceleration_limits' flag can not be set if "
563 "'max_deceleration' is not set or not have valid double values.");
564 updated_limits.has_deceleration_limits = false;
565 }
566 else
567 {
568 changed = true;
569 }
570 }
571 else if (param_name == param_base_name + ".has_jerk_limits")
572 {
573 updated_limits.has_jerk_limits = parameter.get_value<bool>();
574 if (updated_limits.has_jerk_limits && std::isnan(updated_limits.max_jerk))
575 {
576 RCLCPP_WARN(
577 logging_itf->get_logger(),
578 "PARAMETER NOT UPDATED: 'has_jerk_limits' flag can not be set if 'max_jerk' is not set "
579 "or not have valid double values.");
580 updated_limits.has_jerk_limits = false;
581 }
582 else
583 {
584 changed = true;
585 }
586 }
587 else if (param_name == param_base_name + ".has_effort_limits")
588 {
589 updated_limits.has_effort_limits = parameter.get_value<bool>();
590 if (updated_limits.has_effort_limits && std::isnan(updated_limits.max_effort))
591 {
592 RCLCPP_WARN(
593 logging_itf->get_logger(),
594 "PARAMETER NOT UPDATED: 'has_effort_limits' flag can not be set if 'max_effort' is not "
595 "set or not have valid double values.");
596 updated_limits.has_effort_limits = false;
597 }
598 else
599 {
600 changed = true;
601 }
602 }
603 else if (param_name == param_base_name + ".angle_wraparound")
604 {
605 updated_limits.angle_wraparound = parameter.get_value<bool>();
606 if (updated_limits.angle_wraparound && updated_limits.has_position_limits)
607 {
608 RCLCPP_WARN(
609 logging_itf->get_logger(),
610 "PARAMETER NOT UPDATED: 'angle_wraparound' flag can not be set if "
611 "'has_position_limits' flag is set.");
612 updated_limits.angle_wraparound = false;
613 }
614 else
615 {
616 changed = true;
617 }
618 }
619 }
620 catch (const rclcpp::exceptions::InvalidParameterTypeException & e)
621 {
622 RCLCPP_WARN(
623 logging_itf->get_logger(), "PARAMETER NOT UPDATED: Please use the right type: %s",
624 e.what());
625 }
626 }
627
628 return changed;
629}
630
632
664 const std::string & joint_name,
665 const rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & param_itf,
666 const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr & logging_itf,
667 SoftJointLimits & soft_limits)
668{
669 const std::string param_base_name = fmt::format(FMT_COMPILE("joint_limits.{}"), joint_name);
670 try
671 {
672 if (
673 !param_itf->has_parameter(param_base_name + ".has_soft_limits") &&
674 !param_itf->has_parameter(param_base_name + ".k_velocity") &&
675 !param_itf->has_parameter(param_base_name + ".k_position") &&
676 !param_itf->has_parameter(param_base_name + ".soft_lower_limit") &&
677 !param_itf->has_parameter(param_base_name + ".soft_upper_limit"))
678 {
679 RCLCPP_DEBUG(
680 logging_itf->get_logger(),
681 "No soft joint limits specification found for joint '%s' in the parameter server "
682 "(param name: %s).",
683 joint_name.c_str(), param_base_name.c_str());
684 return false;
685 }
686 }
687 catch (const std::exception & ex)
688 {
689 RCLCPP_ERROR(logging_itf->get_logger(), "%s", ex.what());
690 return false;
691 }
692
693 // Override soft limits if complete specification is found
694 if (param_itf->has_parameter(param_base_name + ".has_soft_limits"))
695 {
696 if (
697 param_itf->get_parameter(param_base_name + ".has_soft_limits").as_bool() &&
698 param_itf->has_parameter(param_base_name + ".k_position") &&
699 param_itf->has_parameter(param_base_name + ".k_velocity") &&
700 param_itf->has_parameter(param_base_name + ".soft_lower_limit") &&
701 param_itf->has_parameter(param_base_name + ".soft_upper_limit"))
702 {
703 soft_limits.k_position =
704 param_itf->get_parameter(param_base_name + ".k_position").as_double();
705 soft_limits.k_velocity =
706 param_itf->get_parameter(param_base_name + ".k_velocity").as_double();
707 soft_limits.min_position =
708 param_itf->get_parameter(param_base_name + ".soft_lower_limit").as_double();
709 soft_limits.max_position =
710 param_itf->get_parameter(param_base_name + ".soft_upper_limit").as_double();
711 return true;
712 }
713 }
714
715 return false;
716}
717
731 const std::string & joint_name, const rclcpp::Node::SharedPtr & node,
732 SoftJointLimits & soft_limits)
733{
734 return get_joint_limits(
735 joint_name, node->get_node_parameters_interface(), node->get_node_logging_interface(),
736 soft_limits);
737}
738
752 const std::string & joint_name, const rclcpp_lifecycle::LifecycleNode::SharedPtr & lifecycle_node,
753 SoftJointLimits & soft_limits)
754{
755 return get_joint_limits(
756 joint_name, lifecycle_node->get_node_parameters_interface(),
757 lifecycle_node->get_node_logging_interface(), soft_limits);
758}
759
775 const std::string & joint_name, const std::vector<rclcpp::Parameter> & parameters,
776 const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr & logging_itf,
777 SoftJointLimits & updated_limits)
778{
779 const std::string param_base_name = fmt::format(FMT_COMPILE("joint_limits.{}"), joint_name);
780 bool changed = false;
781
782 for (auto & parameter : parameters)
783 {
784 const std::string param_name = parameter.get_name();
785 try
786 {
787 if (param_name == param_base_name + ".has_soft_limits")
788 {
789 if (!parameter.get_value<bool>())
790 {
791 RCLCPP_WARN(
792 logging_itf->get_logger(),
793 "Parameter 'has_soft_limits' is not set, therefore the limits will not be updated!");
794 return false;
795 }
796 }
797 }
798 catch (const rclcpp::exceptions::InvalidParameterTypeException & e)
799 {
800 RCLCPP_INFO(logging_itf->get_logger(), "Please use the right type: %s", e.what());
801 }
802 }
803
804 for (auto & parameter : parameters)
805 {
806 const std::string param_name = parameter.get_name();
807 try
808 {
809 if (param_name == param_base_name + ".k_position")
810 {
811 changed = updated_limits.k_position != parameter.get_value<double>();
812 updated_limits.k_position = parameter.get_value<double>();
813 }
814 else if (param_name == param_base_name + ".k_velocity")
815 {
816 changed = updated_limits.k_velocity != parameter.get_value<double>();
817 updated_limits.k_velocity = parameter.get_value<double>();
818 }
819 else if (param_name == param_base_name + ".soft_lower_limit")
820 {
821 changed = updated_limits.min_position != parameter.get_value<double>();
822 updated_limits.min_position = parameter.get_value<double>();
823 }
824 else if (param_name == param_base_name + ".soft_upper_limit")
825 {
826 changed = updated_limits.max_position != parameter.get_value<double>();
827 updated_limits.max_position = parameter.get_value<double>();
828 }
829 }
830 catch (const rclcpp::exceptions::InvalidParameterTypeException & e)
831 {
832 RCLCPP_INFO(logging_itf->get_logger(), "Please use the right type: %s", e.what());
833 }
834 }
835
836 return changed;
837}
838
839} // namespace joint_limits
840
841#endif // JOINT_LIMITS__JOINT_LIMITS_ROSPARAM_HPP_
Definition data_structures.hpp:39
bool check_for_limits_update(const std::string &joint_name, const std::vector< rclcpp::Parameter > &parameters, const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr &logging_itf, JointLimits &updated_limits)
Definition joint_limits_rosparam.hpp:433
bool declare_parameters(const std::string &joint_name, const rclcpp::node_interfaces::NodeParametersInterface::SharedPtr &param_itf, const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr &logging_itf)
Definition joint_limits_rosparam.hpp:88
bool get_joint_limits(const std::string &joint_name, const rclcpp::node_interfaces::NodeParametersInterface::SharedPtr &param_itf, const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr &logging_itf, JointLimits &limits)
Populate a JointLimits instance from the node parameters.
Definition joint_limits_rosparam.hpp:227
Definition joint_limits.hpp:35
Definition joint_limits.hpp:113