Control Libraries 6.3.4
Loading...
Searching...
No Matches
Ring.cpp
1#include "dynamical_systems/Ring.hpp"
2
3#include "dynamical_systems/exceptions/EmptyAttractorException.hpp"
4#include "state_representation/exceptions/InvalidParameterException.hpp"
5#include "state_representation/space/cartesian/CartesianTwist.hpp"
6#include "state_representation/exceptions/IncompatibleReferenceFramesException.hpp"
7#include "state_representation/exceptions/EmptyStateException.hpp"
8
9using namespace state_representation;
10
11namespace dynamical_systems {
12
14 center_(std::make_shared<Parameter<CartesianPose>>("center", CartesianPose())),
15 rotation_offset_(std::make_shared<Parameter<CartesianPose>>("rotation_offset", CartesianPose())),
16 radius_(std::make_shared<Parameter<double>>("radius", 1.0)),
17 width_(std::make_shared<Parameter<double>>("width", 0.5)),
18 speed_(std::make_shared<Parameter<double>>("speed", 1.0)),
19 field_strength_(std::make_shared<Parameter<double>>("field_strength", 1.0)),
20 normal_gain_(std::make_shared<Parameter<double>>("normal_gain", 1.0)),
21 angular_gain_(std::make_shared<Parameter<double>>("angular_gain", 1.0)) {
22 this->center_->get_value().set_empty();
23 this->rotation_offset_->set_value(
24 CartesianPose("rotation", Eigen::Quaterniond::Identity(), this->center_->get_value().get_name()));
25 this->parameters_.insert(std::make_pair("center", this->center_));
26 this->parameters_.insert(std::make_pair("rotation_offset", this->rotation_offset_));
27 this->parameters_.insert(std::make_pair("radius", this->radius_));
28 this->parameters_.insert(std::make_pair("width", this->width_));
29 this->parameters_.insert(std::make_pair("speed", this->speed_));
30 this->parameters_.insert(std::make_pair("field_strength", this->field_strength_));
31 this->parameters_.insert(std::make_pair("normal_gain", this->normal_gain_));
32 this->parameters_.insert(std::make_pair("angular_gain", this->angular_gain_));
33}
34
35Ring::Ring(const std::list<std::shared_ptr<state_representation::ParameterInterface>>& parameters) : Ring() {
36 this->set_parameters(parameters);
37}
38
39void Ring::set_center(const CartesianPose& center) {
40 if (center.is_empty()) {
41 throw state_representation::exceptions::EmptyStateException(center.get_name() + " state is empty");
42 }
43 if (this->get_base_frame().is_empty()) {
46 }
47 // validate that the reference frame of the center is always compatible with the DS reference frame
48 if (center.get_reference_frame() != this->get_base_frame().get_name()) {
49 if (center.get_reference_frame() != this->get_base_frame().get_reference_frame()) {
51 "The reference frame of the center " + center.get_name() + " in frame " + center.get_reference_frame()
52 + " is incompatible with the base frame of the dynamical system " + this->get_base_frame().get_name()
53 + " in frame " + this->get_base_frame().get_reference_frame() + "."
54 );
55 }
56 this->center_->set_value(this->get_base_frame().inverse() * center);
57 } else {
58 this->center_->set_value(center);
59 }
60 this->set_rotation_offset(this->get_rotation_offset());
61}
62
63void Ring::set_rotation_offset(const Eigen::Quaterniond& rotation) {
64 auto pose = CartesianPose("rotation", rotation, this->center_->get_value().get_name());
65 this->rotation_offset_->set_value(pose);
66}
67
68Eigen::Quaterniond Ring::get_rotation_offset() const {
69 return this->rotation_offset_->get_value().get_orientation();
70}
71
72void Ring::set_base_frame(const CartesianState& base_frame) {
73 if (base_frame.is_empty()) {
74 throw state_representation::exceptions::EmptyStateException(base_frame.get_name() + " state is empty");
75 }
77 // update reference frame of center
78 if (!this->center_->get_value().is_empty()) {
79 auto center = this->center_->get_value();
80 center.set_reference_frame(base_frame.get_name());
81 this->center_->set_value(center);
82 }
83}
84
85void Ring::validate_and_set_parameter(const std::shared_ptr<ParameterInterface>& parameter) {
86 if (parameter->get_name() == "center") {
87 this->assert_parameter_valid(parameter);
88 this->set_center(std::static_pointer_cast<Parameter<CartesianPose>>(parameter)->get_value());
89 } else if (parameter->get_name() == "rotation_offset") {
90 this->assert_parameter_valid(parameter);
91 this->rotation_offset_->set_value(std::static_pointer_cast<Parameter<CartesianPose>>(parameter)->get_value());
92 } else if (parameter->get_name() == "radius") {
93 this->assert_parameter_valid(parameter);
94 this->radius_->set_value(std::static_pointer_cast<Parameter<double>>(parameter)->get_value());
95 } else if (parameter->get_name() == "width") {
96 this->assert_parameter_valid(parameter);
97 this->width_->set_value(std::static_pointer_cast<Parameter<double>>(parameter)->get_value());
98 } else if (parameter->get_name() == "speed") {
99 this->assert_parameter_valid(parameter);
100 this->speed_->set_value(std::static_pointer_cast<Parameter<double>>(parameter)->get_value());
101 } else if (parameter->get_name() == "field_strength") {
102 this->assert_parameter_valid(parameter);
103 this->field_strength_->set_value(std::static_pointer_cast<Parameter<double>>(parameter)->get_value());
104 } else if (parameter->get_name() == "normal_gain") {
105 this->assert_parameter_valid(parameter);
106 this->normal_gain_->set_value(std::static_pointer_cast<Parameter<double>>(parameter)->get_value());
107 } else if (parameter->get_name() == "angular_gain") {
108 this->assert_parameter_valid(parameter);
109 this->angular_gain_->set_value(std::static_pointer_cast<Parameter<double>>(parameter)->get_value());
110 } else {
112 "No parameter with name '" + parameter->get_name() + "' found"
113 );
114 }
115}
116
117Eigen::Vector3d Ring::calculate_local_linear_velocity(const CartesianPose& pose, double& local_field_strength) const {
118 Eigen::Vector3d local_linear_velocity = Eigen::Vector3d::Zero();
119
120 // get the 2d components of position on the XY plane
121 Eigen::Vector2d position2d(pose.get_position().x(), pose.get_position().y());
122
123 double d = position2d.norm();
124 if (d < 1e-7) {
125 return local_linear_velocity;
126 }
127
128 double re = M_PI_2 * (d - this->radius_->get_value()) / this->width_->get_value();
129 if (re > M_PI_2) {
130 re = M_PI_2;
131 } else if (re < -M_PI_2) {
132 re = -M_PI_2;
133 }
134
135 // calculate the velocity of a point as an orthogonal unit vector, rectified towards the radius based on re
136 Eigen::Matrix2d R;
137 R << -sin(re), -cos(re), cos(re), -sin(re);
138 Eigen::Vector2d velocity2d = R * position2d / d;
139
140 // scale by the nominal speed
141 velocity2d *= this->speed_->get_value();
142
143 // calculate the normal velocity
144 double vz = -this->normal_gain_->get_value() * pose.get_position().z();
145
146 // combine into 3D velocity
147 local_linear_velocity << velocity2d, vz;
148
149 // calculate the field strength and scale the velocity
150 local_field_strength = this->field_strength_->get_value() + (1 - this->field_strength_->get_value()) * cos(re);
151 local_linear_velocity *= local_field_strength;
152
153 return local_linear_velocity;
154}
155
156Eigen::Vector3d Ring::calculate_local_angular_velocity(
157 const CartesianPose& pose, const Eigen::Vector3d& linearVelocity, double local_field_strength
158) const {
159 Eigen::Vector3d local_angular_velocity = Eigen::Vector3d::Zero();
160
161 double theta = atan2(pose.get_position().y(), pose.get_position().x());
162
163 Eigen::Quaterniond qd = Eigen::Quaterniond::Identity();
164 qd.w() = cos(theta / 2);
165 qd.z() = sin(theta / 2);
166
167 if (pose.get_orientation().dot(qd) < 0) {
168 qd.coeffs() = -qd.coeffs();
169 }
170
171 Eigen::Quaterniond deltaQ = qd * pose.get_orientation().conjugate();
172 if (deltaQ.vec().norm() < 1e-7) {
173 return local_angular_velocity;
174 }
175
176 //dOmega = 2 * ln (deltaQ)
177 Eigen::Quaterniond deltaOmega = Eigen::Quaterniond::Identity();
178 deltaOmega.w() = 0;
179 double phi = atan2(deltaQ.vec().norm(), deltaQ.w());
180 deltaOmega.vec() = 2 * deltaQ.vec() * phi / sin(phi);
181
182 local_angular_velocity = this->angular_gain_->get_value() * deltaOmega.vec();
183 local_angular_velocity *= local_field_strength;
184
185 Eigen::Vector2d position2d(pose.get_position().x(), pose.get_position().y());
186 Eigen::Vector2d linear_velocity2d(linearVelocity.x(), linearVelocity.y());
187 if (position2d.norm() < 1e-7 || linear_velocity2d.norm() < 1e-7) {
188 return local_angular_velocity;
189 }
190
191 // clamp linear velocity magnitude to half the position, so that the angular displacement
192 // around the local Z axis caused by the linear velocity stays within one quadrant
193 if (linear_velocity2d.norm() > (0.5 * position2d.norm())) {
194 linear_velocity2d = linear_velocity2d.normalized() * (0.5 * position2d).norm();
195 }
196 double projection = position2d.normalized().dot((position2d + linear_velocity2d).normalized());
197 double dthetaZ = 0;
198 if (1 - abs(projection) > 1e-7) {
199 dthetaZ = acos(projection);
200 }
201 local_angular_velocity.z() += dthetaZ;
202
203 return local_angular_velocity;
204}
205
207 if (this->center_->get_value().is_empty()) {
208 throw exceptions::EmptyAttractorException("The center of the dynamical system is empty.");
209 }
210 // put the point in the reference of the center
211 CartesianPose pose(state);
212 pose = this->center_->get_value().inverse() * pose;
213 // apply the rotation offset
214 pose.set_orientation(pose.get_orientation() * this->get_rotation_offset().conjugate());
215
216 CartesianTwist twist(pose.get_name(), pose.get_reference_frame());
217 double local_field_strength;
218 twist.set_linear_velocity(this->calculate_local_linear_velocity(pose, local_field_strength));
220 this->calculate_local_angular_velocity(
221 pose, twist.get_linear_velocity(), local_field_strength
222 ));
223
224 // transform the twist back to the base reference frame
225 return CartesianState(this->center_->get_value()) * twist;
226}
227}// namespace dynamical_systems
state_representation::CartesianState get_base_frame() const
Return the base frame of the dynamical system.
virtual void set_base_frame(const S &base_frame)
Set the base frame of the dynamical system.
Represent a Ring dynamical system limit cycle to move around a radius within a fixed width.
Definition: Ring.hpp:16
state_representation::CartesianState compute_dynamics(const state_representation::CartesianState &state) const override
Compute the dynamics of the input state. Internal function, to be redefined based on the type of dyna...
Definition: Ring.cpp:206
void set_base_frame(const state_representation::CartesianState &base_frame) override
Set a parameter.
Definition: Ring.cpp:72
Ring()
Empty constructor.
Definition: Ring.cpp:13
Class to define CartesianPose in cartesian space as 3D position and quaternion based orientation.
Class to represent a state in Cartesian space.
void set_orientation(const Eigen::Quaterniond &orientation)
Setter of the orientation.
const Eigen::Vector3d & get_linear_velocity() const
Getter of the linear velocity attribute.
const Eigen::Vector3d & get_position() const
Getter of the position attribute.
static CartesianState Identity(const std::string &name, const std::string &reference="world")
Constructor for the identity CartesianState (identity pose and 0 for the rest)
const Eigen::Quaterniond & get_orientation() const
Getter of the orientation attribute.
void set_linear_velocity(const Eigen::Vector3d &linear_velocity)
Setter of the linear velocity attribute.
void set_angular_velocity(const Eigen::Vector3d &angular_velocity)
Setter of the angular velocity attribute.
Class to define twist in cartesian space as 3D linear and angular velocity vectors.
void assert_parameter_valid(const std::shared_ptr< ParameterInterface > &parameter)
Check if a parameter has the expected type, throw an exception otherwise.
void set_parameters(const ParameterInterfaceList &parameters)
Set parameters from a list of parameters.
ParameterInterfaceMap parameters_
map of parameters by name
virtual void set_reference_frame(const std::string &reference_frame)
Setter of the reference frame.
const std::string & get_reference_frame() const
Getter of the reference frame as const reference.
const std::string & get_name() const
Getter of the name as const reference.
Definition: State.cpp:48
bool is_empty() const
Getter of the empty attribute.
Definition: State.cpp:23
Systems of equations relating state variables to their derivatives.
Definition: Circular.hpp:7
Core state variables and objects.