franky 1.1.4
A High-Level Motion API for Franka
Loading...
Searching...
No Matches
waypoint_motion.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <optional>
4#include <ruckig/ruckig.hpp>
5
7
8namespace franky {
9
13struct MotionPlannerException : std::runtime_error {
14 using std::runtime_error::runtime_error;
15};
16
35template <typename TargetType>
36struct Waypoint {
38
40
41 std::optional<franka::Duration> minimum_time{std::nullopt};
42
43 franka::Duration hold_target_duration{0};
44
45 std::optional<franka::Duration> max_total_duration{std::nullopt};
46};
47
58template <typename ControlSignalType, typename WaypointType, typename TargetType>
59class WaypointMotion : public Motion<ControlSignalType> {
60 static_assert(
61 std::is_base_of_v<Waypoint<TargetType>, WaypointType>, "WaypointType must inherit from Waypoint<TargetType>");
62
63 public:
69 explicit WaypointMotion(std::vector<WaypointType> waypoints, bool return_when_finished = true)
70 : waypoints_(std::move(waypoints)), return_when_finished_(return_when_finished), prev_result_() {}
71
72 [[nodiscard]] const std::vector<WaypointType> &waypoints() const { return waypoints_; }
73
74 [[nodiscard]] bool return_when_finished() const { return return_when_finished_; }
75
76 protected:
77 void initImpl(const RobotState &robot_state, const std::optional<ControlSignalType> &previous_command) override {
78 target_reached_time_ = std::nullopt;
79 waypoint_started_time_ = franka::Duration(0);
80
81 waypoint_iterator_ = waypoints_.begin();
83 if (waypoint_iterator_ != waypoints_.end()) {
84 checkWaypoint(*waypoint_iterator_);
85 setNewWaypoint(robot_state, previous_command, *waypoint_iterator_, input_parameter_);
86 setInputLimits(*waypoint_iterator_, input_parameter_);
87 prev_result_ = ruckig::Result::Working;
88 } else {
89 prev_result_ = ruckig::Result::Finished;
90 }
91 }
92
94 const RobotState &robot_state, franka::Duration time_step, franka::Duration rel_time, franka::Duration abs_time,
95 const std::optional<ControlSignalType> &previous_command) override {
96 const auto expected_time_step = franka::Duration(1);
98 // In this case, we missed a couple of steps for some reason. Hence,
99 // extrapolate the way the robot does if it does not receive data
100 // (constant acceleration model). See
101 // https://frankaemika.github.io/docs/libfranka.html#under-the-hood
102 extrapolateMotion(robot_state, time_step - expected_time_step, input_parameter_, output_parameter_);
103 output_parameter_.pass_to_input(input_parameter_);
104 }
105
106 auto max_time_reached = false;
107 if (waypoint_iterator_ != waypoints_.end() && waypoint_iterator_->max_total_duration.has_value()) {
108 max_time_reached = rel_time - waypoint_started_time_ >= waypoint_iterator_->max_total_duration.value();
109 }
110
111 if (prev_result_ == ruckig::Finished || max_time_reached) {
112 if (!target_reached_time_.has_value()) {
113 target_reached_time_ = rel_time;
114 }
115 if (waypoint_iterator_ != waypoints_.end()) {
116 auto hold_target_duration = waypoint_iterator_->hold_target_duration;
117 if (waypoint_iterator_ + 1 == waypoints_.end()) {
118 // Allow cooldown of motion, so that the low-pass filter has time to
119 // adjust to target values
120 hold_target_duration = std::max(hold_target_duration, franka::Duration(10));
121 }
122 if (rel_time - target_reached_time_.value() >= hold_target_duration || max_time_reached) {
123 target_reached_time_ = std::nullopt;
124 ++waypoint_iterator_;
125 if (waypoint_iterator_ != waypoints_.end()) {
126 checkWaypoint(*waypoint_iterator_);
127 setNewWaypoint(robot_state, previous_command, *waypoint_iterator_, input_parameter_);
128 setInputLimits(*waypoint_iterator_, input_parameter_);
129 waypoint_started_time_ = rel_time;
130 }
131 }
132 }
133 if (waypoint_iterator_ == waypoints_.end()) {
135 if (!return_when_finished_) return command;
136 return franka::MotionFinished(command);
137 }
138 }
139
140 assert(waypoint_iterator_ != waypoints_.end());
141
142 prev_result_ = trajectory_generator_.update(input_parameter_, output_parameter_);
143 if (prev_result_ == ruckig::Result::Working || prev_result_ == ruckig::Result::Finished) {
144 // This is a workaround to prevent NaNs from popping up. Must be some bug
145 // in ruckig.
146 for (int i = 0; i < 7; i++) {
147 if (!input_parameter_.enabled[i]) {
148 output_parameter_.new_position[i] = 0.0;
149 output_parameter_.new_velocity[i] = 0.0;
150 output_parameter_.new_acceleration[i] = 0.0;
151 }
152 }
153 output_parameter_.pass_to_input(input_parameter_);
154 } else {
155 throw MotionPlannerException("Motion planner failed with error code " + std::to_string(prev_result_));
156 }
157
158 return getControlSignal(robot_state, time_step, previous_command, input_parameter_);
159 };
160
161 virtual void initWaypointMotion(
162 const RobotState &robot_state, const std::optional<ControlSignalType> &previous_command,
163 ruckig::InputParameter<7> &input_parameter) = 0;
164
165 virtual void setNewWaypoint(
166 const RobotState &robot_state, const std::optional<ControlSignalType> &previous_command,
167 const WaypointType &new_waypoint, ruckig::InputParameter<7> &input_parameter) = 0;
168
169 virtual void extrapolateMotion(
170 const RobotState &robot_state, const franka::Duration &time_step,
171 const ruckig::InputParameter<7> &input_parameter, ruckig::OutputParameter<7> &output_parameter) const = 0;
172
173 virtual void checkWaypoint(const WaypointType &waypoint) const {}
174
175 [[nodiscard]] virtual std::tuple<Vector7d, Vector7d, Vector7d> getAbsoluteInputLimits() const = 0;
176
178 const RobotState &robot_state, const franka::Duration &time_step,
179 const std::optional<ControlSignalType> &previous_command, const ruckig::InputParameter<7> &input_parameter) = 0;
180
181 virtual void setInputLimits(const WaypointType &waypoint, ruckig::InputParameter<7> &input_parameter) const = 0;
182
183 private:
184 std::vector<WaypointType> waypoints_;
185 bool return_when_finished_{true};
186
187 ruckig::Ruckig<7> trajectory_generator_{Robot::control_rate};
188 ruckig::Result prev_result_;
189 ruckig::InputParameter<7> input_parameter_;
190 ruckig::OutputParameter<7> output_parameter_;
191
192 typename std::vector<WaypointType>::iterator waypoint_iterator_;
193
194 std::optional<franka::Duration> target_reached_time_;
195 franka::Duration waypoint_started_time_;
196};
197
198} // namespace franky
Base class for motions.
Definition motion.hpp:25
Relative dynamics factors.
Definition relative_dynamics_factor.hpp:13
static constexpr double control_rate
Definition robot.hpp:157
A motion following multiple waypoints in a time-optimal way. Works with arbitrary initial conditions.
Definition waypoint_motion.hpp:59
virtual void extrapolateMotion(const RobotState &robot_state, const franka::Duration &time_step, const ruckig::InputParameter< 7 > &input_parameter, ruckig::OutputParameter< 7 > &output_parameter) const =0
virtual void initWaypointMotion(const RobotState &robot_state, const std::optional< ControlSignalType > &previous_command, ruckig::InputParameter< 7 > &input_parameter)=0
virtual void setInputLimits(const WaypointType &waypoint, ruckig::InputParameter< 7 > &input_parameter) const =0
WaypointMotion(std::vector< WaypointType > waypoints, bool return_when_finished=true)
Definition waypoint_motion.hpp:69
bool return_when_finished() const
Definition waypoint_motion.hpp:74
const std::vector< WaypointType > & waypoints() const
Definition waypoint_motion.hpp:72
virtual void checkWaypoint(const WaypointType &waypoint) const
Definition waypoint_motion.hpp:173
virtual ControlSignalType getControlSignal(const RobotState &robot_state, const franka::Duration &time_step, const std::optional< ControlSignalType > &previous_command, const ruckig::InputParameter< 7 > &input_parameter)=0
virtual void setNewWaypoint(const RobotState &robot_state, const std::optional< ControlSignalType > &previous_command, const WaypointType &new_waypoint, ruckig::InputParameter< 7 > &input_parameter)=0
void initImpl(const RobotState &robot_state, const std::optional< ControlSignalType > &previous_command) override
Definition waypoint_motion.hpp:77
ControlSignalType nextCommandImpl(const RobotState &robot_state, franka::Duration time_step, franka::Duration rel_time, franka::Duration abs_time, const std::optional< ControlSignalType > &previous_command) override
Definition waypoint_motion.hpp:93
virtual std::tuple< Vector7d, Vector7d, Vector7d > getAbsoluteInputLimits() const =0
Definition dynamics_limit.cpp:8
std::array< double, dims > toStdD(const Eigen::Matrix< double, dims, 1 > &vector)
Definition util.hpp:18
ControlSignalType
Type of control signal.
Definition control_signal_type.hpp:8
Exception thrown if the motion planner fails.
Definition waypoint_motion.hpp:13
Full state of the robot.
Definition robot_state.hpp:40
A waypoint with a target and optional parameters.
Definition waypoint_motion.hpp:36
std::optional< franka::Duration > max_total_duration
Definition waypoint_motion.hpp:45
franka::Duration hold_target_duration
Definition waypoint_motion.hpp:43
TargetType target
Definition waypoint_motion.hpp:37
RelativeDynamicsFactor relative_dynamics_factor
Definition waypoint_motion.hpp:39
std::optional< franka::Duration > minimum_time
Definition waypoint_motion.hpp:41