Control Libraries 6.3.4
Loading...
Searching...
No Matches
Jacobian.cpp
1#include "state_representation/space/Jacobian.hpp"
2
3#include "state_representation/exceptions/EmptyStateException.hpp"
4#include "state_representation/exceptions/IncompatibleStatesException.hpp"
5
6namespace state_representation {
8 this->State::initialize();
9}
10
11Jacobian::Jacobian(const std::string& robot_name,
12 unsigned int nb_joints,
13 const std::string& frame,
14 const std::string& reference_frame) :
15 State(StateType::JACOBIAN, robot_name),
16 joint_names_(nb_joints),
17 frame_(frame),
18 reference_frame_(reference_frame),
19 rows_(6),
20 cols_(nb_joints) {
21 this->set_joint_names(nb_joints);
22 this->initialize();
23}
24
25Jacobian::Jacobian(const std::string& robot_name,
26 const std::vector<std::string>& joint_names,
27 const std::string& frame,
28 const std::string& reference_frame) :
29 State(StateType::JACOBIAN, robot_name),
30 joint_names_(joint_names),
31 frame_(frame),
32 reference_frame_(reference_frame),
33 rows_(6),
34 cols_(joint_names.size()) {
35 this->initialize();
36}
37
38Jacobian::Jacobian(const std::string& robot_name,
39 const std::string& frame,
40 const Eigen::MatrixXd& data,
41 const std::string& reference_frame) :
42 Jacobian(robot_name, data.cols(), frame, reference_frame) {
43 this->set_data(data);
44}
45
46Jacobian::Jacobian(const std::string& robot_name,
47 const std::vector<std::string>& joint_names,
48 const std::string& frame,
49 const Eigen::MatrixXd& data,
50 const std::string& reference_frame) :
51 Jacobian(robot_name, joint_names, frame, reference_frame) {
52 this->set_data(data);
53}
54
55Jacobian::Jacobian(const Jacobian& jacobian) :
56 State(jacobian),
57 joint_names_(jacobian.joint_names_),
58 frame_(jacobian.frame_),
59 reference_frame_(jacobian.reference_frame_),
60 rows_(jacobian.rows_),
61 cols_(jacobian.cols()),
62 data_(jacobian.data_) {}
63
65 this->State::initialize();
66 this->data_.resize(this->rows_, this->cols());
67 this->data_.setZero();
68}
69
70Jacobian Jacobian::Random(const std::string& robot_name,
71 unsigned int nb_joints,
72 const std::string& frame,
73 const std::string& reference_frame) {
74 Jacobian random(robot_name, nb_joints, frame, reference_frame);
75 random.set_data(Eigen::MatrixXd::Random(random.rows_, random.cols_));
76 return random;
77}
78
79Jacobian Jacobian::Random(const std::string& robot_name,
80 const std::vector<std::string>& joint_names,
81 const std::string& frame,
82 const std::string& reference_frame) {
83 Jacobian random(robot_name, joint_names, frame, reference_frame);
84 random.set_data(Eigen::MatrixXd::Random(random.rows_, random.cols_));
85 return random;
86}
87
88bool Jacobian::is_compatible(const State& state) const {
89 bool compatible = false;
90 switch (state.get_type()) {
91 case StateType::JACOBIAN:
92 // compatibility is assured through the vector of joint names
93 compatible = (this->get_name() == state.get_name())
94 && (this->cols_ == dynamic_cast<const Jacobian&>(state).get_joint_names().size());
95 if (compatible) {
96 for (unsigned int i = 0; i < this->cols_; ++i) {
97 compatible = (compatible && this->joint_names_[i] == dynamic_cast<const Jacobian&>(state).get_joint_names()[i]);
98 }
99 // compatibility is assured through the reference frame and the name of the frame
100 compatible = (compatible && ((this->reference_frame_ == dynamic_cast<const Jacobian&>(state).get_reference_frame())
101 && (this->frame_ == dynamic_cast<const Jacobian&>(state).get_frame())));
102 }
103 break;
104 case StateType::JOINT_STATE:
105 case StateType::JOINT_POSITIONS:
106 case StateType::JOINT_VELOCITIES:
107 case StateType::JOINT_ACCELERATIONS:
108 case StateType::JOINT_TORQUES:
109 // compatibility is assured through the vector of joint names
110 compatible = (this->get_name() == state.get_name())
111 && (this->cols_ == dynamic_cast<const JointState&>(state).get_size());
112 if (compatible) {
113 for (unsigned int i = 0; i < this->cols_; ++i) {
114 compatible = (compatible && this->joint_names_[i] == dynamic_cast<const JointState&>(state).get_names()[i]);
115 }
116 }
117 break;
118 case StateType::CARTESIAN_STATE:
119 case StateType::CARTESIAN_POSE:
120 case StateType::CARTESIAN_TWIST:
121 case StateType::CARTESIAN_ACCELERATION:
122 case StateType::CARTESIAN_WRENCH:
123 // compatibility is assured through the reference frame and the name of the frame
124 compatible = (this->reference_frame_ == dynamic_cast<const CartesianState&>(state).get_reference_frame())
125 && (this->frame_ == dynamic_cast<const CartesianState&>(state).get_name());
126 break;
127 default:
128 break;
129 }
130 return compatible;
131}
132
133void Jacobian::set_reference_frame(const CartesianPose& reference_frame) {
134 *this = reference_frame * (*this);
135}
136
138 Jacobian result(*this);
139 result.cols_ = this->rows_;
140 result.rows_ = this->cols_;
141 result.set_data(result.data().transpose());
142 return result;
143}
144
146 if (this->rows_ != this->cols_) {
148 "The Jacobian matrix is not invertible, use the pseudoinverse function instead");
149 }
150 Jacobian result(*this);
151 result.cols_ = this->cols_;
152 result.rows_ = this->rows_;
153 result.set_data(result.data().inverse());
154 return result;
155}
156
158 Jacobian result(*this);
159 Eigen::MatrixXd pinv = this->data().completeOrthogonalDecomposition().pseudoInverse();
160 result.cols_ = pinv.cols();
161 result.rows_ = pinv.rows();
162 result.set_data(pinv);
163 return result;
164}
165
166Eigen::MatrixXd Jacobian::operator*(const Eigen::MatrixXd& matrix) const {
167 if (this->is_empty()) {
168 throw EmptyStateException(this->get_name() + " state is empty");
169 }
170 if (matrix.rows() != this->cols_) {
171 throw IncompatibleSizeException("Input matrix is of incorrect size, expected "
172 + std::to_string(this->cols_) + " rows, got " + std::to_string(matrix.rows()));
173 }
174 return this->data() * matrix;
175}
176
177Eigen::MatrixXd Jacobian::operator*(const Jacobian& jacobian) const {
178 if (!this->is_compatible(jacobian)) {
179 throw IncompatibleStatesException("The two Jacobian matrices are not compatible");
180 }
181 // multiply with the data of the second Jacobian
182 return (*this) * jacobian.data();
183}
184
186 if (this->is_empty()) {
187 throw EmptyStateException(this->get_name() + " state is empty");
188 }
189 if (dq.is_empty()) {
190 throw EmptyStateException(dq.get_name() + " state is empty");
191 }
192 if (!this->is_compatible(dq)) {
193 throw IncompatibleStatesException("The Jacobian and the input JointVelocities are incompatible");
194 }
195 Eigen::Matrix<double, 6, 1> twist = (*this) * dq.data();
196 CartesianTwist result(this->frame_, twist, this->reference_frame_);
197 return result;
198}
199
201 if (this->is_empty()) {
202 throw EmptyStateException(this->get_name() + " state is empty");
203 }
204 if (twist.is_empty()) {
205 throw EmptyStateException(twist.get_name() + " state is empty");
206 }
207 if (!this->is_compatible(twist)) {
208 throw IncompatibleStatesException("The Jacobian and the input CartesianTwist are incompatible");
209 }
210 Eigen::VectorXd joint_velocities = (*this) * twist.data();
211 JointVelocities result(this->get_name(), this->get_joint_names(), joint_velocities);
212 return result;
213}
214
216 if (this->is_empty()) {
217 throw EmptyStateException(this->get_name() + " state is empty");
218 }
219 if (wrench.is_empty()) {
220 throw EmptyStateException(wrench.get_name() + " state is empty");
221 }
222 if (!this->is_compatible(wrench)) {
223 throw IncompatibleStatesException("The Jacobian and the input CartesianWrench are incompatible");
224 }
225 Eigen::VectorXd joint_torques = (*this) * wrench.data();
226 JointTorques result(this->get_name(), this->get_joint_names(), joint_torques);
227 return result;
228}
229
230Eigen::MatrixXd Jacobian::solve(const Eigen::MatrixXd& matrix) const {
231 if (this->is_empty()) {
232 throw EmptyStateException(this->get_name() + " state is empty");
233 }
234 if (this->rows_ != matrix.rows()) {
235 throw IncompatibleSizeException("Input matrix is of incorrect size, expected "
236 + std::to_string(this->rows_) + " rows, got " + std::to_string(matrix.rows()));
237 }
238 return this->data().colPivHouseholderQr().solve(matrix);
239}
240
242 if (this->is_empty()) {
243 throw EmptyStateException(this->get_name() + " state is empty");
244 }
245 if (twist.is_empty()) {
246 throw EmptyStateException(twist.get_name() + " state is empty");
247 }
248 if (!this->is_compatible(twist)) {
249 throw IncompatibleStatesException("The Jacobian and the input CartesianTwist are incompatible");
250 }
251 // this uses the solve operation instead of using the inverse or pseudo-inverse of the Jacobian
252 Eigen::VectorXd joint_velocities = this->solve(twist.data());
253 // return a JointVelocities state
254 JointVelocities result(this->get_name(), this->get_joint_names(), joint_velocities);
255 return result;
256}
257
259 Jacobian result(*this);
260 return result;
261}
262
263std::ostream& operator<<(std::ostream& os, const Jacobian& jacobian) {
264 if (jacobian.is_empty()) {
265 os << "Empty Jacobian";
266 } else {
267 os << jacobian.get_name() << " Jacobian associated to " << jacobian.frame_;
268 os << ", expressed in " << jacobian.reference_frame_ << std::endl;
269 os << "joint names: [";
270 for (auto& n : jacobian.get_joint_names()) { os << n << ", "; }
271 os << "]" << std::endl;
272 os << "number of rows: " << jacobian.rows_ << std::endl;
273 os << "number of columns: " << jacobian.cols_ << std::endl;
274 for (unsigned int i = 0; i < jacobian.rows_; ++i) {
275 os << "| " << jacobian(i, 0);
276 for (unsigned int j = 1; j < jacobian.cols_; ++j) {
277 os << ", " << jacobian(i, j);
278 }
279 os << " |";
280 if (i != jacobian.rows_ - 1) {
281 os << std::endl;
282 }
283 }
284 }
285 return os;
286}
287
288Jacobian operator*(const CartesianPose& pose, const Jacobian& jacobian) {
289 // check compatibility
290 if (jacobian.is_empty()) {
291 throw EmptyStateException(jacobian.get_name() + " state is empty");
292 }
293 if (pose.is_empty()) {
294 throw EmptyStateException(pose.get_name() + " state is empty");
295 }
296 if (pose.get_name() != jacobian.get_reference_frame()) {
297 throw IncompatibleStatesException("The Jacobian and the input CartesianPose are incompatible, expected pose of "
298 + jacobian.get_reference_frame() + " got " + pose.get_name());
299 }
300 // number of rows of the jacobian should be 6 (incorrect if it has been transposed before)
301 if (jacobian.rows_ != 6) {
303 "The Jacobian and the input CartesianPose are incompatible, the Jacobian has probably been transposed before");
304 }
305 Jacobian result(jacobian);
306 // change the reference frame of all the columns
307 for (unsigned int i = 0; i < jacobian.cols_; ++i) {
308 // update position part
309 result.data_.col(i).head(3) = pose.get_orientation() * jacobian.data_.col(i).head(3);
310 // update orientation part
311 result.data_.col(i).tail(3) = pose.get_orientation() * jacobian.data_.col(i).tail(3);
312 }
313 // change the reference frame
314 result.reference_frame_ = pose.get_reference_frame();
315 return result;
316}
317
318Eigen::MatrixXd operator*(const Eigen::MatrixXd& matrix, const Jacobian& jacobian) {
319 // check compatibility
320 if (jacobian.is_empty()) {
321 throw EmptyStateException(jacobian.get_name() + " state is empty");
322 }
323 if (matrix.cols() != jacobian.rows()) {
324 throw IncompatibleStatesException("The matrix and the Jacobian have incompatible sizes");
325 }
326 return matrix * jacobian.data();
327}
328}// namespace state_representation
Class to define CartesianPose in cartesian space as 3D position and quaternion based orientation.
Class to represent a state in Cartesian space.
const Eigen::Quaterniond & get_orientation() const
Getter of the orientation attribute.
Class to define twist in cartesian space as 3D linear and angular velocity vectors.
Eigen::VectorXd data() const override
Returns the twist data as an Eigen vector.
Class to define wrench in cartesian space as 3D force and torque vectors.
Eigen::VectorXd data() const override
Returns the wrench data as an Eigen vector.
Class to define a robot Jacobian matrix.
Definition: Jacobian.hpp:20
Jacobian copy() const
Return a copy of the JointPositions.
Definition: Jacobian.cpp:258
const std::vector< std::string > & get_joint_names() const
Getter of the joint_names attribute.
Definition: Jacobian.hpp:360
const Eigen::MatrixXd & data() const
Getter of the data attribute.
Definition: Jacobian.hpp:392
Jacobian pseudoinverse() const
Return the pseudoinverse of the Jacobian matrix.
Definition: Jacobian.cpp:157
unsigned int cols() const
Getter of the number of columns attribute.
Definition: Jacobian.hpp:348
Eigen::MatrixXd solve(const Eigen::MatrixXd &matrix) const
Solve the system X = inv(J)*M to obtain X which is more efficient than multiplying with the pseudo-in...
Definition: Jacobian.cpp:230
const std::string & get_reference_frame() const
Getter of the reference_frame attribute.
Definition: Jacobian.hpp:388
unsigned int rows() const
Getter of the number of rows attribute.
Definition: Jacobian.hpp:344
void set_reference_frame(const CartesianPose &reference_frame)
Setter of the reference_frame attribute from a CartesianPose Update the value of the data matrix acco...
Definition: Jacobian.cpp:133
const std::string & get_frame() const
Getter of the frame attribute.
Definition: Jacobian.hpp:384
friend Jacobian operator*(const CartesianPose &pose, const Jacobian &jacobian)
Overload the * operator with a CartesianPose on left side. This is equivalent to a changing of refere...
Definition: Jacobian.cpp:288
Jacobian inverse() const
Return the inverse of the Jacobian matrix If the matrix is not invertible, an error is thrown advisin...
Definition: Jacobian.cpp:145
void set_joint_names(unsigned int nb_joints)
Setter of the joint_names attribute from the number of joints.
Definition: Jacobian.hpp:364
void set_data(const Eigen::MatrixXd &data) override
Setter of the data attribute.
Definition: Jacobian.hpp:396
bool is_compatible(const State &state) const override
Check if the Jacobian matrix is compatible for operations with the state given as argument.
Definition: Jacobian.cpp:88
Jacobian()
Empty constructor for a Jacobian.
Definition: Jacobian.cpp:7
Jacobian transpose() const
Return the transpose of the Jacobian matrix.
Definition: Jacobian.cpp:137
void initialize() override
Initialize the matrix to a zero value.
Definition: Jacobian.cpp:64
static Jacobian Random(const std::string &robot_name, unsigned int nb_joints, const std::string &frame, const std::string &reference_frame="world")
Constructor for a random Jacobian.
Definition: Jacobian.cpp:70
Class to define a state in joint space.
Definition: JointState.hpp:36
unsigned int get_size() const
Getter of the size from the attributes.
Definition: JointState.hpp:656
Class to define torques of the joints.
Class to define velocities of the joints.
Eigen::VectorXd data() const override
Returns the velocities data as an Eigen vector.
const std::string & get_reference_frame() const
Getter of the reference frame as const reference.
Abstract class to represent a state.
Definition: State.hpp:25
virtual void initialize()
Initialize the State to a zero value.
Definition: State.cpp:61
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
Core state variables and objects.
CartesianAcceleration operator*(const CartesianState &state, const CartesianAcceleration &acceleration)
std::ostream & operator<<(std::ostream &os, const Ellipsoid &ellipsoid)
Definition: Ellipsoid.cpp:185
StateType
The class types inheriting from State.
Definition: StateType.hpp:13