TrajectoryFollowingController.cpp
Go to the documentation of this file.
2 
3 #include <algorithm>
4 #include <cmath>
5 #include <limits>
6 #include <vector>
7 
8 #include <SimoxUtility/math/convert/mat4f_to_pos.h>
9 #include <SimoxUtility/math/convert/mat4f_to_rpy.h>
10 
14 #include <ArmarXCore/interface/serialization/Eigen/Eigen_fdi.h>
15 
18 
23 #include <armarx/navigation/trajectory_control/global/aron/TrajectoryFollowingControllerParams.aron.generated.h>
26 
28 {
29  // TrajectoryFollowingControllerParams
30 
33  {
35  }
36 
39  {
40  arondto::TrajectoryFollowingControllerParams dto;
41 
44 
45  return dto.toAron();
46  }
47 
50  {
51  arondto::TrajectoryFollowingControllerParams dto;
52  dto.fromAron(dict);
53 
56 
57  return bo;
58  }
59 
60  // TrajectoryFollowingController
61 
63  params(params),
64  pidPos(params.pidPos.Kp,
65  params.pidPos.Ki,
66  params.pidPos.Kd,
67  std::numeric_limits<double>::max(),
68  std::numeric_limits<double>::max(),
69  false,
70  std::vector<bool>{false, false, false}),
71  pidPosTarget(params.pidPos.Kp,
72  params.pidPos.Ki,
73  params.pidPos.Kd,
76  false,
77  std::vector<bool>{false, false, false}),
78  pidOri(params.pidOri.Kp,
79  params.pidOri.Ki,
80  params.pidOri.Kd,
83  false,
84  std::vector<bool>{true, true, true}),
85  pidOriTarget(params.pidOri.Kp,
86  params.pidOri.Ki,
87  params.pidOri.Kd,
90  false,
91  std::vector<bool>{true, true, true})
92  {
93  ARMARX_IMPORTANT << "Trajectory following controller params: "
94  << VAROUT(params.limits.linear) << ", " << VAROUT(params.limits.angular);
95  }
96 
97  core::Twist
99  {
100  if (params.limits.linear == 0 or params.limits.angular == 0)
101  {
102  return core::Twist{.linear = Eigen::Vector3f::Zero(),
103  .angular = Eigen::Vector3f::Zero()};
104  }
105 
108 
109  const core::Twist limits{.linear = Eigen::Vector3f::Ones() * params.limits.linear,
110  .angular = Eigen::Vector3f::Ones() * params.limits.angular};
111 
112  ARMARX_CHECK(limits.linear.allFinite());
113  ARMARX_CHECK(limits.angular.allFinite());
114 
115  // for all entries, scale should be less than 1
116  const float scalePos = twist.linear.norm() / limits.linear.norm();
117  const auto scaleOri = twist.angular.cwiseAbs().cwiseQuotient(limits.angular.cwiseAbs());
118 
119  // ARMARX_CHECK(scalePos.allFinite());
120  ARMARX_CHECK(scaleOri.allFinite());
121 
122  const float scaleMax = std::max(scalePos, scaleOri.maxCoeff());
123 
124  if (scaleMax < 1.0F) // both linear and angular velocity in bounds?
125  {
126  return twist;
127  }
128 
129  ARMARX_CHECK(not std::isnan(scaleMax));
130 
131  // scale such that no limit is violated
132  twist.linear /= scaleMax;
133  twist.angular /= scaleMax;
134 
135  // constexpr float eps = 0.001;
136 
137  // pedantic checks
138  // ARMARX_CHECK_LESS_EQUAL(std::abs(twist.linear.x()), params.limits.linear + eps);
139  //ARMARX_CHECK_LESS_EQUAL(std::abs(twist.linear.y()), params.limits.linear + eps);
140  //ARMARX_CHECK_LESS_EQUAL(std::abs(twist.linear.z()), params.limits.linear + eps);
141  //ARMARX_CHECK_LESS_EQUAL(std::abs(twist.angular.x()), params.limits.angular + eps);
142  //ARMARX_CHECK_LESS_EQUAL(std::abs(twist.angular.y()), params.limits.angular + eps);
143  //ARMARX_CHECK_LESS_EQUAL(std::abs(twist.angular.z()), params.limits.angular + eps);
144 
145  return twist;
146  }
147 
148  void
150  {
151  params.limits = limits;
152  }
153 
156  const core::Pose& global_T_robot)
157  {
158  using simox::math::mat4f_to_pos;
159  using simox::math::mat4f_to_rpy;
160 
161  const core::Pose currentPose(global_T_robot);
162  const float currentOrientation = mat4f_to_rpy(currentPose.matrix()).z();
163 
164  if (trajectory.points().empty())
165  {
166  ARMARX_INFO << "Trajectory is empty.";
169  .dropPoint = {.waypoint = {.pose = core::Pose::Identity()}, .velocity = 0},
170  .isFinalSegment = true,
171  .currentOrientation = currentOrientation,
172  .desiredOrientation = currentOrientation,
173  .orientationError = 0,
174  .positionError = 0};
175  }
176 
177 
178  const auto projectedPose = trajectory.getProjection(
179  currentPose.translation(), core::VelocityInterpolation::LinearInterpolation);
180 
181 
182  pidPos.update(mat4f_to_pos(currentPose.matrix()),
183  mat4f_to_pos(projectedPose.projection.waypoint.pose.matrix()));
184  pidOri.update(mat4f_to_rpy(currentPose.matrix()),
185  mat4f_to_rpy(projectedPose.projection.waypoint.pose.matrix()));
186 
187  const float desiredOrientation =
188  mat4f_to_rpy(projectedPose.projection.waypoint.pose.matrix()).z();
189 
190  const core::Twist twist = [&]() -> core::Twist
191  {
192  // on the final segment, bahavior differs
193  if (projectedPose.segment == core::Projection::Segment::FINAL)
194  {
195 
196  ARMARX_VERBOSE << deactivateSpam(1) << "final segment";
197  // TODO fairly inefficient to do this every time
198  pidPos.reset();
199  pidOri.reset();
200 
201  pidPosTarget.update(currentPose.translation(),
202  trajectory.points().back().waypoint.pose.translation());
203 
204  pidOriTarget.update(
205  mat4f_to_rpy(currentPose.matrix()),
206  mat4f_to_rpy(trajectory.points().back().waypoint.pose.matrix()));
207 
208  return core::Twist{.linear = pidPosTarget.getControlValue(),
209  .angular = pidOriTarget.getControlValue()};
210  }
211 
212  // pidPosTarget not used yet
213  // TODO fairly inefficient to do this every time
214  pidPosTarget.reset();
215 
216  // the "standard" case following the trajectory
217  const Eigen::Vector3f desiredMovementDirection =
218  (projectedPose.wayPointAfter.waypoint.pose.translation() -
219  projectedPose.wayPointBefore.waypoint.pose.translation())
220  .normalized();
221 
222  const float ffVel = projectedPose.projection.velocity;
223  ARMARX_CHECK_FINITE(ffVel);
224  ARMARX_CHECK_LESS(ffVel, 3000); // 3 m/s should be sufficient, right?
225 
226  const auto feedforwardVelocity = desiredMovementDirection * ffVel;
227 
228  ARMARX_VERBOSE << deactivateSpam(1) << "Feed forward direction "
229  << feedforwardVelocity.normalized();
230  ARMARX_VERBOSE << deactivateSpam(1) << "Feed forward velocity " << feedforwardVelocity;
231  ARMARX_VERBOSE << deactivateSpam(1) << "Control value " << pidPos.getControlValue();
232 
233  return core::Twist{.linear = pidPos.getControlValue() + feedforwardVelocity,
234  .angular = pidOri.getControlValue()};
235  }();
236 
237  const auto twistLimited = applyTwistLimits(twist);
238  ARMARX_VERBOSE << deactivateSpam(1) << "Twist limited " << twistLimited.linear.transpose();
239  ARMARX_VERBOSE << deactivateSpam(1) << "Twist angular " << twistLimited.angular.transpose();
240 
241  // convert to the robot's base frame
242  const auto& twistGlobal = twistLimited;
243 
244  core::Twist twistLocal;
245  twistLocal.linear = global_T_robot.linear().inverse() * twistGlobal.linear;
246  // TODO if not in 2D, then this must be changed!
247  twistLocal.angular = twistGlobal.angular;
248 
249 
250  const bool isFinalSegment = projectedPose.segment == core::Projection::Segment::FINAL;
251 
253  .twist = twistLocal,
254  .dropPoint = projectedPose.projection,
255  .isFinalSegment = isFinalSegment,
256  .currentOrientation = currentOrientation,
257  .desiredOrientation = desiredOrientation,
258  .orientationError = std::abs(currentOrientation - desiredOrientation),
259  .positionError = (global_T_robot.translation() -
260  trajectory.points().back().waypoint.pose.translation())
261  .head<2>()
262  .norm()};
263  }
264 
265 } // namespace armarx::navigation::traj_ctrl::global
armarx::navigation::core::GlobalTrajectory
Definition: Trajectory.h:70
armarx::navigation::traj_ctrl::global::TrajectoryFollowingController::updateTwistLimits
void updateTwistLimits(const core::TwistLimits &limits)
Definition: TrajectoryFollowingController.cpp:149
aron_conversions.h
ARMARX_VERBOSE
#define ARMARX_VERBOSE
Definition: Logging.h:187
armarx::navigation::traj_ctrl::global::TrajectoryControllerResult
Definition: TrajectoryController.h:40
armarx::navigation::traj_ctrl::global::TrajectoryFollowingController::control
TrajectoryControllerResult control(const core::GlobalTrajectory &trajectory, const core::Pose &global_T_robot) override
Definition: TrajectoryFollowingController.cpp:155
ARMARX_IMPORTANT
#define ARMARX_IMPORTANT
Definition: Logging.h:190
armarx::navigation::core::VelocityInterpolation::LinearInterpolation
@ LinearInterpolation
armarx::MultiDimPIDControllerTemplate::reset
void reset()
Definition: MultiDimPIDController.h:214
armarx::navigation::core::Pose
Eigen::Isometry3f Pose
Definition: basic_types.h:31
basic_types.h
armarx::navigation::traj_ctrl::global::TrajectoryFollowingController::applyTwistLimits
core::Twist applyTwistLimits(core::Twist twist)
Definition: TrajectoryFollowingController.cpp:98
armarx::navigation::core::Twist::Zero
static Twist Zero()
Definition: basic_types.cpp:13
armarx::navigation::traj_ctrl::global::fromAron
void fromAron(const arondto::TrajectoryControllerParams &dto, TrajectoryControllerParams &bo)
Definition: aron_conversions.cpp:21
armarx::MultiDimPIDControllerTemplate::update
void update(const double deltaSec, const PIDVectorX &measuredValue, const PIDVectorX &targetValue)
Definition: MultiDimPIDController.h:79
armarx::max
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
Definition: VectorHelpers.h:297
armarx::navigation::traj_ctrl::global::Algorithms
Algorithms
Definition: core.h:30
ARMARX_CHECK_LESS
#define ARMARX_CHECK_LESS(lhs, rhs)
This macro evaluates whether lhs is less (<) than rhs and if it turns out to be false it will throw a...
Definition: ExpressionException.h:102
armarx::navigation::core::TwistLimits::linear
float linear
Definition: types.h:82
TrajectoryFollowingController.h
armarx::navigation::traj_ctrl::global::TrajectoryFollowingController::TrajectoryFollowingController
TrajectoryFollowingController(const Params &params)
Definition: TrajectoryFollowingController.cpp:62
Dict.h
armarx::navigation::core::Projection::Segment::FINAL
@ FINAL
armarx::navigation::core::TwistLimits::angular
float angular
Definition: types.h:83
StringHelpers.h
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::navigation::core::Twist
Definition: basic_types.h:53
TrajectoryController.h
armarx::navigation::traj_ctrl::global::TrajectoryFollowingControllerParams::toAron
aron::data::DictPtr toAron() const override
Definition: TrajectoryFollowingController.cpp:38
deactivateSpam
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition: Logging.cpp:75
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
core.h
MultiDimPIDController.h
armarx::abs
std::vector< T > abs(const std::vector< T > &v)
Definition: VectorHelpers.h:281
ARMARX_CHECK_FINITE
#define ARMARX_CHECK_FINITE(number)
This macro evaluates whether number is finite (not nan or inf) and if it turns out to be false it wil...
Definition: ExpressionException.h:182
armarx::navigation::core::TwistLimits
Definition: types.h:80
max
T max(T t1, T t2)
Definition: gdiam.h:51
armarx::navigation::traj_ctrl::global::toAron
void toAron(arondto::TrajectoryControllerParams &dto, const TrajectoryControllerParams &bo)
Definition: aron_conversions.cpp:15
ARMARX_CHECK_POSITIVE
#define ARMARX_CHECK_POSITIVE(number)
This macro evaluates whether number is positive (> 0) and if it turns out to be false it will throw a...
Definition: ExpressionException.h:145
ExpressionException.h
armarx::navigation::traj_ctrl::global::TrajectoryFollowingControllerParams::FromAron
static TrajectoryFollowingControllerParams FromAron(const aron::data::DictPtr &dict)
Definition: TrajectoryFollowingController.cpp:49
armarx::navigation::core::Twist::linear
LinearVelocity linear
Definition: basic_types.h:55
armarx::aron::data::DictPtr
std::shared_ptr< Dict > DictPtr
Definition: Dict.h:41
armarx::navigation::traj_ctrl::global::TrajectoryFollowingControllerParams
Definition: TrajectoryFollowingController.h:40
armarx::navigation::traj_ctrl::global::TrajectoryFollowingControllerParams::algorithm
Algorithms algorithm() const override
Definition: TrajectoryFollowingController.cpp:32
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
std
Definition: Application.h:66
armarx::MultiDimPIDControllerTemplate::getControlValue
const PIDVectorX & getControlValue() const
Definition: MultiDimPIDController.h:201
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:198
F
Definition: ExportDialogControllerTest.cpp:18
armarx::navigation::core::Twist::angular
AngularVelocity angular
Definition: basic_types.h:56
armarx::navigation::traj_ctrl::global::TrajectoryControllerResult::twist
core::Twist twist
Definition: TrajectoryController.h:42
armarx::navigation::traj_ctrl::global::Algorithms::TrajectoryFollowingController
@ TrajectoryFollowingController
armarx::navigation::core::GlobalTrajectory::getProjection
Projection getProjection(const Position &point, const VelocityInterpolation &velocityInterpolation) const
Definition: Trajectory.cpp:245
Logging.h
armarx::navigation::traj_ctrl::global::TrajectoryControllerParams::limits
core::TwistLimits limits
Definition: TrajectoryController.h:54
Trajectory.h
armarx::navigation::traj_ctrl::global
This file is part of ArmarX.
Definition: aron_conversions.cpp:11
armarx::navigation::core::GlobalTrajectory::points
const std::vector< GlobalTrajectoryPoint > & points() const
Definition: Trajectory.cpp:734
types.h
armarx::aron::bo
const std::optional< BoT > & bo
Definition: aron_conversions.h:174