rm_control
Loading...
Searching...
No Matches
hybrid_joint_limits_interface.h
Go to the documentation of this file.
1//
2// Created by wk on 2026/1/3.
3//
4
5#pragma once
6
7#include <algorithm>
8#include <cassert>
9#include <cmath>
10#include <limits>
11
12#include <ros/duration.h>
13
14#include <hardware_interface/internal/resource_manager.h>
15#include <hardware_interface/joint_command_interface.h>
16
17#include <joint_limits_interface/joint_limits.h>
18#include <joint_limits_interface/joint_limits_interface.h>
19#include <joint_limits_interface/joint_limits_interface_exception.h>
20
22
23namespace rm_control
24{
26{
27public:
29 const joint_limits_interface::JointLimits& limits)
30 : hjh_(hjh), limits_(limits)
31 {
32 if (!limits.has_velocity_limits)
33 {
34 throw joint_limits_interface::JointLimitsInterfaceException("Cannot enforce limits for joint '" + getName() +
35 "'. It has no velocity limits specification.");
36 }
37 if (!limits.has_effort_limits)
38 {
39 throw joint_limits_interface::JointLimitsInterfaceException("Cannot enforce limits for joint '" + getName() +
40 "'. It has no efforts limits specification.");
41 }
42
43 if (limits_.has_position_limits)
44 {
45 min_pos_limit_ = limits_.min_position;
46 max_pos_limit_ = limits_.max_position;
47 }
48 else
49 {
50 min_pos_limit_ = -std::numeric_limits<double>::max();
51 max_pos_limit_ = std::numeric_limits<double>::max();
52 }
53 }
54
56 std::string getName() const
57 {
58 return hjh_.getName();
59 }
60
64 void enforceLimits(const ros::Duration& period)
65 {
66 using joint_limits_interface::internal::saturate;
67 double min_eff = -limits_.max_effort;
68 double max_eff = limits_.max_effort;
69
70 if (limits_.has_position_limits)
71 {
72 const double pos = hjh_.getPosition();
73 if (pos < limits_.min_position)
74 min_eff = 0.0;
75 else if (pos > limits_.max_position)
76 max_eff = 0.0;
77 }
78
79 const double vel = hjh_.getVelocity();
80 if (vel < -limits_.max_velocity)
81 min_eff = 0.0;
82 else if (vel > limits_.max_velocity)
83 max_eff = 0.0;
84
85 if (std::isnan(prev_pos_cmd_))
86 prev_pos_cmd_ = hjh_.getPosition();
87
88 double min_pos, max_pos;
89 if (limits_.has_velocity_limits)
90 {
91 const double delta_pos = limits_.max_velocity * period.toSec();
92 min_pos = std::max(prev_pos_cmd_ - delta_pos, min_pos_limit_);
93 max_pos = std::min(prev_pos_cmd_ + delta_pos, max_pos_limit_);
94 }
95 else
96 {
97 min_pos = min_pos_limit_;
98 max_pos = max_pos_limit_;
99 }
100
101 const double pos_cmd = saturate(hjh_.getPositionDesired(), min_pos, max_pos);
102 prev_pos_cmd_ = pos_cmd;
103
104 // Velocity bounds
105 double vel_low{};
106 double vel_high{};
107
108 if (limits_.has_acceleration_limits)
109 {
110 assert(period.toSec() > 0.0);
111 const double dt = period.toSec();
112
113 vel_low = std::max(prev_vel_cmd_ - limits_.max_acceleration * dt, -limits_.max_velocity);
114 vel_high = std::min(prev_vel_cmd_ + limits_.max_acceleration * dt, limits_.max_velocity);
115 }
116 else
117 {
118 vel_low = -limits_.max_velocity;
119 vel_high = limits_.max_velocity;
120 }
121
122 // Saturate velocity command according to limits
123 const double vel_cmd = saturate(hjh_.getVelocityDesired(), vel_low, vel_high);
124 prev_vel_cmd_ = vel_cmd;
125
126 hjh_.setCommand(pos_cmd, vel_cmd, hjh_.getKp(), hjh_.getKd(), saturate(hjh_.getFeedforward(), min_eff, max_eff));
127 }
128
132 void reset()
133 {
134 prev_pos_cmd_ = std::numeric_limits<double>::quiet_NaN();
135 }
136
137private:
139 joint_limits_interface::JointLimits limits_;
140
141 double min_pos_limit_, max_pos_limit_;
142
143 double prev_pos_cmd_ = { std::numeric_limits<double>::quiet_NaN() };
144 double prev_vel_cmd_ = { std::numeric_limits<double>::quiet_NaN() };
145};
146
148{
149public:
151
153 const joint_limits_interface::JointLimits& limits,
154 const joint_limits_interface::SoftJointLimits& soft_limits)
155 : hjh_(hjh), limits_(limits), soft_limits_(soft_limits)
156 {
157 if (!limits.has_velocity_limits)
158 {
159 throw joint_limits_interface::JointLimitsInterfaceException("Cannot enforce limits for joint '" + getName() +
160 "'. It has no velocity limits specification.");
161 }
162 if (!limits.has_effort_limits)
163 {
164 throw joint_limits_interface::JointLimitsInterfaceException("Cannot enforce limits for joint '" + getName() +
165 "'. It has no effort limits specification.");
166 }
167 }
168
170 std::string getName() const
171 {
172 return hjh_.getName();
173 }
174
180 void enforceLimits(const ros::Duration& period)
181 {
182 using joint_limits_interface::internal::saturate;
183
184 // Effort Interface limits
185 // Current state
186 double pos = hjh_.getPosition();
187 double vel = hjh_.getVelocity();
188
189 // Velocity bounds
190 double soft_min_vel{};
191 double soft_max_vel{};
192
193 if (limits_.has_position_limits)
194 {
195 // Velocity bounds depend on the velocity limit and the proximity to the position limit
196 soft_min_vel = saturate(-soft_limits_.k_position * (pos - soft_limits_.min_position), -limits_.max_velocity,
197 limits_.max_velocity);
198
199 soft_max_vel = saturate(-soft_limits_.k_position * (pos - soft_limits_.max_position), -limits_.max_velocity,
200 limits_.max_velocity);
201 }
202 else
203 {
204 // No position limits, eg. continuous joints
205 soft_min_vel = -limits_.max_velocity;
206 soft_max_vel = limits_.max_velocity;
207 }
208
209 // Effort bounds depend on the velocity and effort bounds
210 const double soft_min_eff =
211 saturate(-soft_limits_.k_velocity * (vel - soft_min_vel), -limits_.max_effort, limits_.max_effort);
212
213 const double soft_max_eff =
214 saturate(-soft_limits_.k_velocity * (vel - soft_max_vel), -limits_.max_effort, limits_.max_effort);
215
216 // Saturate effort command according to bounds
217 const double eff_cmd = saturate(hjh_.getFeedforward(), soft_min_eff, soft_max_eff);
218
219 assert(period.toSec() > 0.0);
220 // Current position
221 if (std::isnan(prev_pos_cmd_))
222 {
223 prev_pos_cmd_ = hjh_.getPosition();
224 } // Happens only once at initialization
225 pos = prev_pos_cmd_;
226
227 if (limits_.has_position_limits)
228 {
229 // Velocity bounds depend on the velocity limit and the proximity to the position limit
230 soft_min_vel = saturate(-soft_limits_.k_position * (pos - soft_limits_.min_position), -limits_.max_velocity,
231 limits_.max_velocity);
232
233 soft_max_vel = saturate(-soft_limits_.k_position * (pos - soft_limits_.max_position), -limits_.max_velocity,
234 limits_.max_velocity);
235 }
236 else
237 {
238 // No position limits, eg. continuous joints
239 soft_min_vel = -limits_.max_velocity;
240 soft_max_vel = limits_.max_velocity;
241 }
242
243 // Position Interface limits
244 // Position bounds
245 const double dt = period.toSec();
246 double pos_low = pos + soft_min_vel * dt;
247 double pos_high = pos + soft_max_vel * dt;
248
249 if (limits_.has_position_limits)
250 {
251 // This extra measure safeguards against pathological cases, like when the soft limit lies beyond the hard limit
252 pos_low = std::max(pos_low, limits_.min_position);
253 pos_high = std::min(pos_high, limits_.max_position);
254 }
255
256 // Saturate position command according to bounds
257 const double pos_cmd = saturate(hjh_.getPositionDesired(), pos_low, pos_high);
258
259 // Cache variables
260 prev_pos_cmd_ = pos_cmd;
261
262 // Velocity Interface limits
263 double min_vel{}, max_vel{};
264 if (limits_.has_position_limits)
265 {
266 // Velocity bounds depend on the velocity limit and the proximity to the position limit.
267 pos = hjh_.getPosition();
268 min_vel = saturate(-soft_limits_.k_position * (pos - soft_limits_.min_position), -max_vel_limit_, max_vel_limit_);
269 max_vel = saturate(-soft_limits_.k_position * (pos - soft_limits_.max_position), -max_vel_limit_, max_vel_limit_);
270 }
271 else
272 {
273 min_vel = -max_vel_limit_;
274 max_vel = max_vel_limit_;
275 }
276
277 if (limits_.has_acceleration_limits)
278 {
279 vel = hjh_.getVelocity();
280 const double delta_t = period.toSec();
281 min_vel = std::max(vel - limits_.max_acceleration * delta_t, min_vel);
282 max_vel = std::min(vel + limits_.max_acceleration * delta_t, max_vel);
283 }
284
285 hjh_.setCommand(pos_cmd, saturate(hjh_.getVelocityDesired(), min_vel, max_vel), hjh_.getKp(), hjh_.getKd(), eff_cmd);
286 }
287
291 void reset()
292 {
293 prev_pos_cmd_ = std::numeric_limits<double>::quiet_NaN();
294 }
295
296private:
298 joint_limits_interface::JointLimits limits_;
299 joint_limits_interface::SoftJointLimits soft_limits_;
300
301 double prev_pos_cmd_ = { std::numeric_limits<double>::quiet_NaN() };
302 double max_vel_limit_{};
303};
304
306class HybridJointSaturationInterface : public joint_limits_interface::JointLimitsInterface<HybridJointSaturationHandle>
307{
308public:
312 void reset()
313 {
314 for (auto&& resource_name_and_handle : this->resource_map_)
315 {
316 resource_name_and_handle.second.reset();
317 }
318 }
319};
320class HybridJointSoftLimitsInterface : public joint_limits_interface::JointLimitsInterface<HybridJointSoftLimitsHandle>
321{
322public:
326 void reset()
327 {
328 for (auto&& resource_name_and_handle : this->resource_map_)
329 {
330 resource_name_and_handle.second.reset();
331 }
332 }
333};
334} // namespace rm_control
Definition hybrid_joint_interface.h:11
double getFeedforward()
Definition hybrid_joint_interface.h:97
double getVelocityDesired()
Definition hybrid_joint_interface.h:82
void setCommand(double pos_des, double vel_des, double kp, double kd, double ff)
Definition hybrid_joint_interface.h:69
double getPositionDesired()
Definition hybrid_joint_interface.h:77
double getKd()
Definition hybrid_joint_interface.h:92
double getKp()
Definition hybrid_joint_interface.h:87
Definition hybrid_joint_limits_interface.h:26
std::string getName() const
Definition hybrid_joint_limits_interface.h:56
void enforceLimits(const ros::Duration &period)
Enforce position, velocity, and effort limits for a joint that is not subject to soft limits.
Definition hybrid_joint_limits_interface.h:64
void reset()
Reset state, in case of mode switch or e-stop.
Definition hybrid_joint_limits_interface.h:132
HybridJointSaturationHandle(const rm_control::HybridJointHandle &hjh, const joint_limits_interface::JointLimits &limits)
Definition hybrid_joint_limits_interface.h:28
Definition hybrid_joint_limits_interface.h:307
void reset()
Reset all managed handles.
Definition hybrid_joint_limits_interface.h:312
Definition hybrid_joint_limits_interface.h:148
HybridJointSoftLimitsHandle(const rm_control::HybridJointHandle &hjh, const joint_limits_interface::JointLimits &limits, const joint_limits_interface::SoftJointLimits &soft_limits)
Definition hybrid_joint_limits_interface.h:152
std::string getName() const
Definition hybrid_joint_limits_interface.h:170
void enforceLimits(const ros::Duration &period)
Enforce position, velocity and effort limits for a joint subject to soft limits.
Definition hybrid_joint_limits_interface.h:180
void reset()
Reset state, in case of mode switch or e-stop.
Definition hybrid_joint_limits_interface.h:291
Definition hybrid_joint_limits_interface.h:321
void reset()
Reset all managed handles.
Definition hybrid_joint_limits_interface.h:326
Definition actuator_extra_interface.h:44