ros2_control - galactic
Loading...
Searching...
No Matches
joint_limits_interface.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_INTERFACE__JOINT_LIMITS_INTERFACE_HPP_
18#define JOINT_LIMITS_INTERFACE__JOINT_LIMITS_INTERFACE_HPP_
19
20#include <hardware_interface/joint_handle.hpp>
21#include <hardware_interface/types/hardware_interface_type_values.hpp>
22
23#include <rclcpp/duration.hpp>
24#include <rclcpp/rclcpp.hpp>
25
26#include <rcppmath/clamp.hpp>
27
28#include <algorithm>
29#include <cassert>
30#include <cmath>
31#include <limits>
32#include <memory>
33#include <string>
34
35#include "joint_limits_interface/joint_limits.hpp"
36#include "joint_limits_interface/joint_limits_interface_exception.hpp"
37
39{
45{
46public:
48 : prev_pos_(std::numeric_limits<double>::quiet_NaN()),
49 prev_vel_(0.0),
52 jcmdh_("position_command")
53 {
54 }
55
57 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jcmdh,
58 const JointLimits & limits)
59 : jposh_(jposh),
61 jcmdh_(jcmdh),
62 limits_(limits),
63 prev_pos_(std::numeric_limits<double>::quiet_NaN()),
64 prev_vel_(0.0)
65 {
66 }
67
69 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jvelh,
70 const hardware_interface::JointHandle & jcmdh, const JointLimits & limits)
71 : jposh_(jposh),
72 jvelh_(jvelh),
73 jcmdh_(jcmdh),
74 limits_(limits),
75 prev_pos_(std::numeric_limits<double>::quiet_NaN()),
76 prev_vel_(0.0)
77 {
78 }
79
81 std::string get_name() const
82 {
83 return jposh_ ? jposh_.get_name()
84 : jvelh_ ? jvelh_.get_name() : jcmdh_ ? jcmdh_.get_name() : std::string();
85 }
86
88 virtual void enforce_limits(const rclcpp::Duration & period) = 0;
89
91 virtual void reset()
92 {
93 prev_pos_ = std::numeric_limits<double>::quiet_NaN();
94 prev_vel_ = 0.0;
95 }
96
97protected:
98 hardware_interface::JointHandle jposh_;
99 hardware_interface::JointHandle jvelh_;
100 hardware_interface::JointHandle jcmdh_;
102
103 // stored state - track position and velocity of last update
104 double prev_pos_;
105 double prev_vel_;
106
108
112 double get_velocity(const rclcpp::Duration & period) const
113 {
114 // if we have a handle to a velocity state we can directly return state velocity
115 // otherwise we will estimate velocity from previous position (command or state)
116 return jvelh_ ? jvelh_.get_value() : (jposh_.get_value() - prev_pos_) / period.seconds();
117 }
118};
119
124{
125public:
127
129 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jcmdh,
130 const JointLimits & limits, const SoftJointLimits & soft_limits)
131 : JointLimitHandle(jposh, jcmdh, limits), soft_limits_(soft_limits)
132 {
133 }
134
136 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jvelh,
137 const hardware_interface::JointHandle & jcmdh, const JointLimits & limits,
138 const SoftJointLimits & soft_limits)
139 : JointLimitHandle(jposh, jvelh, jcmdh, limits), soft_limits_(soft_limits)
140 {
141 }
142
143protected:
145};
146
150{
151public:
153
155 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jcmdh,
156 const JointLimits & limits)
157 : JointLimitHandle(jposh, jcmdh, limits)
158 {
159 if (limits_.has_position_limits)
160 {
161 min_pos_limit_ = limits_.min_position;
162 max_pos_limit_ = limits_.max_position;
163 }
164 else
165 {
166 min_pos_limit_ = -std::numeric_limits<double>::max();
167 max_pos_limit_ = std::numeric_limits<double>::max();
168 }
169 }
170
172
175 void enforce_limits(const rclcpp::Duration & period)
176 {
177 if (std::isnan(prev_pos_))
178 {
179 prev_pos_ = jposh_.get_value();
180 }
181
182 double min_pos, max_pos;
183 if (limits_.has_velocity_limits)
184 {
185 // enforce velocity limits
186 // set constraints on where the position can be based on the
187 // max velocity times seconds since last update
188 const double delta_pos = limits_.max_velocity * period.seconds();
189 min_pos = std::max(prev_pos_ - delta_pos, min_pos_limit_);
190 max_pos = std::min(prev_pos_ + delta_pos, max_pos_limit_);
191 }
192 else
193 {
194 // no velocity limit, so position is simply limited to set extents (our imposed soft limits)
195 min_pos = min_pos_limit_;
196 max_pos = max_pos_limit_;
197 }
198
199 // clamp command position to our computed min/max position
200 const double cmd = rcppmath::clamp(jcmdh_.get_value(), min_pos, max_pos);
201 jcmdh_.set_value(cmd);
202
203 prev_pos_ = cmd;
204 }
205
206private:
207 double min_pos_limit_, max_pos_limit_;
208};
209
211
239// TODO(anyone): Leverage %Reflexxes Type II library for acceleration limits handling?
241{
242public:
244
246 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jcmdh,
248 const joint_limits_interface::SoftJointLimits & soft_limits)
249 : JointSoftLimitsHandle(jposh, jcmdh, limits, soft_limits)
250 {
251 if (!limits.has_velocity_limits)
252 {
254 "Cannot enforce limits for joint '" + get_name() +
255 "'. It has no velocity limits specification.");
256 }
257 }
258
260
265 void enforce_limits(const rclcpp::Duration & period) override
266 {
267 assert(period.seconds() > 0.0);
268
269 // Current position
270 if (std::isnan(prev_pos_))
271 {
272 // Happens only once at initialization
273 prev_pos_ = jposh_.get_value();
274 }
275 const double pos = prev_pos_;
276
277 // Velocity bounds
278 double soft_min_vel;
279 double soft_max_vel;
280
281 if (limits_.has_position_limits)
282 {
283 // Velocity bounds depend on the velocity limit and the proximity to the position limit
284 soft_min_vel = rcppmath::clamp(
285 -soft_limits_.k_position * (pos - soft_limits_.min_position), -limits_.max_velocity,
286 limits_.max_velocity);
287
288 soft_max_vel = rcppmath::clamp(
289 -soft_limits_.k_position * (pos - soft_limits_.max_position), -limits_.max_velocity,
290 limits_.max_velocity);
291 }
292 else
293 {
294 // No position limits, eg. continuous joints
295 soft_min_vel = -limits_.max_velocity;
296 soft_max_vel = limits_.max_velocity;
297 }
298
299 // Position bounds
300 const double dt = period.seconds();
301 double pos_low = pos + soft_min_vel * dt;
302 double pos_high = pos + soft_max_vel * dt;
303
304 if (limits_.has_position_limits)
305 {
306 // This extra measure safeguards against pathological cases, like when the soft limit lies
307 // beyond the hard limit
308 pos_low = std::max(pos_low, limits_.min_position);
309 pos_high = std::min(pos_high, limits_.max_position);
310 }
311
312 // Saturate position command according to bounds
313 const double pos_cmd = rcppmath::clamp(jcmdh_.get_value(), pos_low, pos_high);
314 jcmdh_.set_value(pos_cmd);
315
316 // Cache variables
317 // todo: shouldn't this just be pos_cmd? why call into the command handle to
318 // get what we have in the above line?
319 prev_pos_ = jcmdh_.get_value();
320 }
321};
322
328{
329public:
331
333 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jvelh,
334 const hardware_interface::JointHandle & jcmdh,
336 : JointLimitHandle(jposh, jvelh, jcmdh, limits)
337 {
338 if (!limits.has_velocity_limits)
339 {
341 "Cannot enforce limits for joint '" + get_name() +
342 "'. It has no velocity limits specification.");
343 }
344 if (!limits.has_effort_limits)
345 {
347 "Cannot enforce limits for joint '" + get_name() +
348 "'. It has no efforts limits specification.");
349 }
350 }
351
353 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jcmdh,
356 jposh, hardware_interface::JointHandle(hardware_interface::HW_IF_VELOCITY), jcmdh, limits)
357 {
358 }
359
366 void enforce_limits(const rclcpp::Duration & period) override
367 {
368 double min_eff = -limits_.max_effort;
369 double max_eff = limits_.max_effort;
370
371 if (limits_.has_position_limits)
372 {
373 const double pos = jposh_.get_value();
374 if (pos < limits_.min_position)
375 {
376 min_eff = 0.0;
377 }
378 else if (pos > limits_.max_position)
379 {
380 max_eff = 0.0;
381 }
382 }
383
384 const double vel = get_velocity(period);
385 if (vel < -limits_.max_velocity)
386 {
387 min_eff = 0.0;
388 }
389 else if (vel > limits_.max_velocity)
390 {
391 max_eff = 0.0;
392 }
393
394 double clamped = rcppmath::clamp(jcmdh_.get_value(), min_eff, max_eff);
395 jcmdh_.set_value(clamped);
396 }
397};
398
400// TODO(anyone): This class is untested!. Update unit tests accordingly.
402{
403public:
405
407 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jvelh,
408 const hardware_interface::JointHandle & jcmdh,
410 const joint_limits_interface::SoftJointLimits & soft_limits)
411 : JointSoftLimitsHandle(jposh, jvelh, jcmdh, limits, soft_limits)
412 {
413 if (!limits.has_velocity_limits)
414 {
416 "Cannot enforce limits for joint '" + get_name() +
417 "'. It has no velocity limits specification.");
418 }
419 if (!limits.has_effort_limits)
420 {
422 "Cannot enforce limits for joint '" + get_name() +
423 "'. It has no effort limits specification.");
424 }
425 }
426
428 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jcmdh,
430 const joint_limits_interface::SoftJointLimits & soft_limits)
432 jposh, hardware_interface::JointHandle(hardware_interface::HW_IF_VELOCITY), jcmdh, limits,
433 soft_limits)
434 {
435 }
436
438
444 void enforce_limits(const rclcpp::Duration & period) override
445 {
446 // Current state
447 const double pos = jposh_.get_value();
448 const double vel = get_velocity(period);
449
450 // Velocity bounds
451 double soft_min_vel;
452 double soft_max_vel;
453
454 if (limits_.has_position_limits)
455 {
456 // Velocity bounds depend on the velocity limit and the proximity to the position limit
457 soft_min_vel = rcppmath::clamp(
458 -soft_limits_.k_position * (pos - soft_limits_.min_position), -limits_.max_velocity,
459 limits_.max_velocity);
460
461 soft_max_vel = rcppmath::clamp(
462 -soft_limits_.k_position * (pos - soft_limits_.max_position), -limits_.max_velocity,
463 limits_.max_velocity);
464 }
465 else
466 {
467 // No position limits, eg. continuous joints
468 soft_min_vel = -limits_.max_velocity;
469 soft_max_vel = limits_.max_velocity;
470 }
471
472 // Effort bounds depend on the velocity and effort bounds
473 const double soft_min_eff = rcppmath::clamp(
474 -soft_limits_.k_velocity * (vel - soft_min_vel), -limits_.max_effort, limits_.max_effort);
475
476 const double soft_max_eff = rcppmath::clamp(
477 -soft_limits_.k_velocity * (vel - soft_max_vel), -limits_.max_effort, limits_.max_effort);
478
479 // Saturate effort command according to bounds
480 const double eff_cmd = rcppmath::clamp(jcmdh_.get_value(), soft_min_eff, soft_max_eff);
481 jcmdh_.set_value(eff_cmd);
482 }
483};
484
487{
488public:
490
492 const hardware_interface::JointHandle & jvelh, // currently unused
493 const hardware_interface::JointHandle & jcmdh,
496 hardware_interface::JointHandle(hardware_interface::HW_IF_POSITION), jvelh, jcmdh, limits)
497 {
498 if (!limits.has_velocity_limits)
499 {
501 "Cannot enforce limits for joint '" + get_name() +
502 "'. It has no velocity limits specification.");
503 }
504 }
505
507 const hardware_interface::JointHandle & jcmdh,
510 hardware_interface::JointHandle(hardware_interface::HW_IF_POSITION),
511 hardware_interface::JointHandle(hardware_interface::HW_IF_VELOCITY), jcmdh, limits)
512 {
513 if (!limits.has_velocity_limits)
514 {
516 "Cannot enforce limits for joint '" + get_name() +
517 "'. It has no velocity limits specification.");
518 }
519 }
520
522
525 void enforce_limits(const rclcpp::Duration & period) override
526 {
527 // Velocity bounds
528 double vel_low;
529 double vel_high;
530
531 if (limits_.has_acceleration_limits)
532 {
533 assert(period.seconds() > 0.0);
534 const double dt = period.seconds();
535
536 vel_low = std::max(prev_vel_ - limits_.max_acceleration * dt, -limits_.max_velocity);
537 vel_high = std::min(prev_vel_ + limits_.max_acceleration * dt, limits_.max_velocity);
538 }
539 else
540 {
541 vel_low = -limits_.max_velocity;
542 vel_high = limits_.max_velocity;
543 }
544
545 // Saturate velocity command according to limits
546 const double vel_cmd = rcppmath::clamp(jcmdh_.get_value(), vel_low, vel_high);
547 jcmdh_.set_value(vel_cmd);
548
549 // Cache variables
550 prev_vel_ = jcmdh_.get_value();
551 }
552};
553
559{
560public:
562
564 const hardware_interface::JointHandle & jposh, const hardware_interface::JointHandle & jvelh,
565 const hardware_interface::JointHandle & jcmdh,
567 const joint_limits_interface::SoftJointLimits & soft_limits)
568 : JointSoftLimitsHandle(jposh, jvelh, jcmdh, limits, soft_limits)
569 {
570 if (limits.has_velocity_limits)
571 {
572 max_vel_limit_ = limits.max_velocity;
573 }
574 else
575 {
576 max_vel_limit_ = std::numeric_limits<double>::max();
577 }
578 }
579
586 void enforce_limits(const rclcpp::Duration & period)
587 {
588 double min_vel, max_vel;
589 if (limits_.has_position_limits)
590 {
591 // Velocity bounds depend on the velocity limit and the proximity to the position limit.
592 const double pos = jposh_.get_value();
593 min_vel = rcppmath::clamp(
594 -soft_limits_.k_position * (pos - soft_limits_.min_position), -max_vel_limit_,
595 max_vel_limit_);
596 max_vel = rcppmath::clamp(
597 -soft_limits_.k_position * (pos - soft_limits_.max_position), -max_vel_limit_,
598 max_vel_limit_);
599 }
600 else
601 {
602 min_vel = -max_vel_limit_;
603 max_vel = max_vel_limit_;
604 }
605
606 if (limits_.has_acceleration_limits)
607 {
608 const double vel = get_velocity(period);
609 const double delta_t = period.seconds();
610 min_vel = std::max(vel - limits_.max_acceleration * delta_t, min_vel);
611 max_vel = std::min(vel + limits_.max_acceleration * delta_t, max_vel);
612 }
613
614 jcmdh_.set_value(rcppmath::clamp(jcmdh_.get_value(), min_vel, max_vel));
615 }
616
617private:
618 double max_vel_limit_;
619};
620
621// TODO(anyone): Port this to ROS 2
622// //**
623// * Interface for enforcing joint limits.
624// *
625// * \tparam HandleType %Handle type. Must implement the following methods:
626// * \code
627// * void enforce_limits();
628// * std::string get_name() const;
629// * \endcode
630// */
631// template<class HandleType>
632// class joint_limits_interface::JointLimitsInterface
633// : public hardware_interface::ResourceManager<HandleType>
634// {
635// public:
636// HandleType getHandle(const std::string & name)
637// {
638// // Rethrow exception with a meaningful type
639// try {
640// return this->hardware_interface::ResourceManager<HandleType>::getHandle(name);
641// } catch (const std::logic_error & e) {
642// throw joint_limits_interface::JointLimitsInterfaceException(e.what());
643// }
644// }
645//
646// /** \name Real-Time Safe Functions
647// *\{*/
648// /** Enforce limits for all managed handles. */
649// void enforce_limits(const rclcpp::Duration & period)
650// {
651// for (auto && resource_name_and_handle : this->resource_map_) {
652// resource_name_and_handle.second.enforce_limits(period);
653// }
654// }
655// /*\}*/
656// };
657//
658// /** Interface for enforcing limits on a position-controlled joint through saturation. */
659// class PositionJointSaturationInterface
660// : public joint_limits_interface::JointLimitsInterface<PositionJointSaturationHandle>
661// {
662// public:
663// /** \name Real-Time Safe Functions
664// *\{*/
665// /** Reset all managed handles. */
666// void reset()
667// {
668// for (auto && resource_name_and_handle : this->resource_map_) {
669// resource_name_and_handle.second.reset();
670// }
671// }
672// /*\}*/
673// };
674//
675// /** Interface for enforcing limits on a position-controlled joint with soft position limits. */
676// class PositionJointSoftLimitsInterface
677// : public joint_limits_interface::JointLimitsInterface<PositionJointSoftLimitsHandle>
678// {
679// public:
680// /** \name Real-Time Safe Functions
681// *\{*/
682// /** Reset all managed handles. */
683// void reset()
684// {
685// for (auto && resource_name_and_handle : this->resource_map_) {
686// resource_name_and_handle.second.reset();
687// }
688// }
689// /*\}*/
690// };
691//
692// /** Interface for enforcing limits on an effort-controlled joint through saturation. */
693// class EffortJointSaturationInterface
694// : public joint_limits_interface::JointLimitsInterface<EffortJointSaturationHandle>
695// {
696// };
697//
698// /** Interface for enforcing limits on an effort-controlled joint with soft position limits. */
699// class EffortJointSoftLimitsInterface
700// : public joint_limits_interface::JointLimitsInterface<EffortJointSoftLimitsHandle>
701// {
702// };
703//
704// /** Interface for enforcing limits on a velocity-controlled joint through saturation. */
705// class VelocityJointSaturationInterface
706// : public joint_limits_interface::JointLimitsInterface<VelocityJointSaturationHandle>
707// {
708// };
709//
710// /** Interface for enforcing limits on a velocity-controlled joint with soft position limits. */
711// class VelocityJointSoftLimitsInterface
712// : public joint_limits_interface::JointLimitsInterface<VelocityJointSoftLimitsHandle>
713// {
714// };
715} // namespace joint_limits_interface
716
717#endif // JOINT_LIMITS_INTERFACE__JOINT_LIMITS_INTERFACE_HPP_
Definition joint_limits_interface.hpp:328
void enforce_limits(const rclcpp::Duration &period) override
Definition joint_limits_interface.hpp:366
A handle used to enforce position, velocity and effort limits of an effort-controlled joint.
Definition joint_limits_interface.hpp:402
void enforce_limits(const rclcpp::Duration &period) override
Enforce position, velocity and effort limits for a joint subject to soft limits.
Definition joint_limits_interface.hpp:444
Definition joint_limits_interface.hpp:45
virtual void reset()
Clear stored state, causing it to reset next iteration.
Definition joint_limits_interface.hpp:91
double get_velocity(const rclcpp::Duration &period) const
Return velocity for limit calculations.
Definition joint_limits_interface.hpp:112
virtual void enforce_limits(const rclcpp::Duration &period)=0
Sub-class implementation of limit enforcing policy.
std::string get_name() const
Definition joint_limits_interface.hpp:81
An exception related to a JointLimitsInterface.
Definition joint_limits_interface_exception.hpp:24
Definition joint_limits_interface.hpp:124
Definition joint_limits_interface.hpp:150
void enforce_limits(const rclcpp::Duration &period)
Enforce position and velocity limits for a joint that is not subject to soft limits.
Definition joint_limits_interface.hpp:175
A handle used to enforce position and velocity limits of a position-controlled joint.
Definition joint_limits_interface.hpp:241
void enforce_limits(const rclcpp::Duration &period) override
Enforce position and velocity limits for a joint subject to soft limits.
Definition joint_limits_interface.hpp:265
A handle used to enforce velocity and acceleration limits of a velocity-controlled joint.
Definition joint_limits_interface.hpp:487
void enforce_limits(const rclcpp::Duration &period) override
Enforce joint velocity and acceleration limits.
Definition joint_limits_interface.hpp:525
Definition joint_limits_interface.hpp:559
void enforce_limits(const rclcpp::Duration &period)
Definition joint_limits_interface.hpp:586
constexpr char HW_IF_VELOCITY[]
Constant defining velocity interface.
Definition hardware_interface_type_values.hpp:23
constexpr char HW_IF_POSITION[]
Constant defining position interface.
Definition hardware_interface_type_values.hpp:21
Definition joint_limits.hpp:21
Definition joint_limits.hpp:23
Definition joint_limits.hpp:56