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