-
Couldn't load subscription status.
- Fork 11
Feature: End-Effector Workspace Pose and Velocity (Linear and Angular) Factor #24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
764b127
7cbc765
38302ae
7f48b89
413a11c
81c1bce
a75e596
c2cb57e
77461c2
ed1ce40
33482c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| /** | ||
| * @file WorkspacePoseVelocityPrior.h | ||
| * @brief Prior defined on the workspace pose and velocity of final joint | ||
| *(end-effector) of a robot given its state in configuration space | ||
| * @author Matthew King-Smith | ||
| * @date May 16, 2023 | ||
| **/ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <gpmp2/kinematics/Arm.h> | ||
| #include <gtsam/base/Matrix.h> | ||
| #include <gtsam/base/Vector.h> | ||
| #include <gtsam/geometry/Pose3.h> | ||
| #include <gtsam/nonlinear/NonlinearFactor.h> | ||
|
|
||
| #include <iostream> | ||
| #include <vector> | ||
|
|
||
| namespace gpmp2 { | ||
|
|
||
| /** | ||
| * binary factor Gaussian prior defined on the workspace pose and velocities | ||
| */ | ||
| class WorkspacePoseVelocityPrior | ||
| : public gtsam::NoiseModelFactor2<gtsam::Vector, gtsam::Vector> { | ||
| private: | ||
| // typedefs | ||
| typedef WorkspacePoseVelocityPrior This; | ||
| typedef gtsam::NoiseModelFactor2<gtsam::Vector, gtsam::Vector> Base; | ||
|
|
||
| // arm | ||
| Arm arm_; | ||
|
|
||
| // desired workspace pose | ||
| gtsam::Pose3 des_pose_; | ||
|
|
||
| // desired velocity (linear and angular) | ||
| gtsam::Vector6 des_vel_; | ||
|
|
||
| public: | ||
| /// shorthand for a smart pointer to a factor | ||
| typedef std::shared_ptr<This> shared_ptr; | ||
|
|
||
| /// Default constructor | ||
| WorkspacePoseVelocityPrior() {} | ||
|
|
||
| /** | ||
| * Constructor | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add documentation for all parameters. |
||
| * @param cost_model cost function covariance | ||
| * @param des_vel desired velocity (linear and angular) | ||
| */ | ||
| WorkspacePoseVelocityPrior(gtsam::Key poseKey, gtsam::Key velKey, | ||
| const gtsam::SharedNoiseModel& cost_model, | ||
| const Arm& arm, const gtsam::Pose3& des_pose, | ||
| const gtsam::Vector6& des_vel) | ||
| : Base(cost_model, poseKey, velKey), | ||
| arm_(arm), | ||
| des_pose_(des_pose), | ||
| des_vel_(des_vel) {} | ||
|
|
||
| ~WorkspacePoseVelocityPrior() {} | ||
|
|
||
| /// error function | ||
| gtsam::Vector evaluateError( | ||
| const gtsam::Vector& joint_conf, const gtsam::Vector& joint_rates, | ||
| gtsam::OptionalMatrixType H1 = nullptr, | ||
| gtsam::OptionalMatrixType H2 = nullptr) const override { | ||
| using namespace gtsam; | ||
|
|
||
| // fk | ||
| std::vector<Pose3> joint_pose; | ||
| std::vector<Vector6> joint_vel; | ||
| std::vector<Matrix> J_jpx_jp, J_jvx_jp, J_jvx_jv; | ||
| arm_.forwardKinematics(joint_conf, joint_rates, joint_pose, &joint_vel, | ||
| &J_jpx_jp, &J_jvx_jp, &J_jvx_jv); | ||
|
|
||
| Matrix66 H_ep; | ||
| Vector pose_error = des_pose_.logmap(joint_pose[arm_.dof() - 1], {}, H_ep); | ||
| Vector vel_error = des_vel_ - joint_vel[arm_.dof() - 1]; | ||
| if (H1) { | ||
| // Jacobian for the joint positions | ||
| *H1 = (Matrix(12, arm_.dof()) << H_ep * J_jpx_jp[arm_.dof() - 1],// | ||
| - J_jvx_jp[arm_.dof() - 1]).finished(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some weird formatting issue is happening here. Can you please reformat the file? |
||
| } | ||
| if (H2) { | ||
| // Jacobian for the joint rates | ||
| *H2 = (Matrix(12, arm_.dof()) << Matrix::Zero(6, arm_.dof()), // | ||
| -J_jvx_jv[arm_.dof() - 1]).finished(); | ||
| } | ||
| Vector12 tot_result; | ||
| tot_result << pose_error, vel_error; | ||
| return tot_result; | ||
| } | ||
|
|
||
| /// @return a deep copy of this factor | ||
| gtsam::NonlinearFactor::shared_ptr clone() const override { | ||
| return std::static_pointer_cast<gtsam::NonlinearFactor>( | ||
| gtsam::NonlinearFactor::shared_ptr(new This(*this))); | ||
| } | ||
|
|
||
| /** print contents */ | ||
| void print(const std::string& s = "", | ||
| const gtsam::KeyFormatter& keyFormatter = | ||
| gtsam::DefaultKeyFormatter) const { | ||
| std::cout << s << "WorkspacePoseVelocityPrior :" << std::endl; | ||
| Base::print("", keyFormatter); | ||
| std::cout << "desired end-effector pose : "; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: capitalize the first letter so the output looks prettier? |
||
| des_pose_.print(); // << std::endl; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kill the comment if the std::endl is not being used. |
||
| std::cout << "desired end-effector velocity : " << des_vel_ << std::endl; | ||
| } | ||
|
|
||
| private: | ||
| #ifdef GPMP2_ENABLE_BOOST_SERIALIZATION | ||
| /** Serialization function */ | ||
| friend class boost::serialization::access; | ||
| template <class ARCHIVE> | ||
| void serialize(ARCHIVE& ar, const unsigned int version) { | ||
| ar& boost::serialization::make_nvp( | ||
| "NoiseModelFactor1", boost::serialization::base_object<Base>(*this)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this should NoiseModelFactor2 and not NoiseModelFactor1 |
||
| } | ||
| #endif | ||
| }; | ||
|
|
||
| } // namespace gpmp2 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| /** | ||
| * @file testWorkspacePoseVelocityPrior.cpp | ||
| * @author Matthew King-Smith | ||
| **/ | ||
|
|
||
| #include <CppUnitLite/TestHarness.h> | ||
| #include <gpmp2/kinematics/WorkspacePoseVelocityPrior.h> | ||
| #include <gtsam/base/Matrix.h> | ||
| #include <gtsam/base/Testable.h> | ||
| #include <gtsam/base/numericalDerivative.h> | ||
| #include <gtsam/inference/Symbol.h> | ||
| #include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h> | ||
| #include <gtsam/nonlinear/NonlinearFactorGraph.h> | ||
| #include <gtsam/nonlinear/Values.h> | ||
|
|
||
| #include <iostream> | ||
|
|
||
| using namespace std; | ||
| using namespace gtsam; | ||
| using namespace gpmp2; | ||
|
|
||
| /* ************************************************************************** */ | ||
| TEST(WorkspacePoseVelocityPrior, error) { | ||
| Vector2 a(1, 1), alpha(M_PI / 2, 0), d(0, 0); | ||
| Arm arm = Arm(2, a, alpha, d); | ||
| Vector2 q; | ||
| Vector2 qdot; | ||
| Pose3 des_pose; | ||
| // Vector6 des_vel; | ||
| // WorkspacePoseVelocityPrior factor; | ||
| Vector actual, expect; | ||
| Matrix H_pose_exp, H_pose_act, H_vel_exp, H_vel_act; | ||
| noiseModel::Gaussian::shared_ptr cost_model = | ||
| noiseModel::Isotropic::Sigma(12, 1.0); | ||
|
|
||
| q = Vector2(M_PI / 4.0, -M_PI / 2); | ||
| qdot = (Vector2() << 0.1, 0.1).finished(); | ||
| des_pose = Pose3(); | ||
| Vector6 des_vel = (Vector6() << 0, 0, 0, 0, 0, 0).finished(); | ||
| WorkspacePoseVelocityPrior factor(0, 0, cost_model, arm, des_pose, des_vel); | ||
| actual = factor.evaluateError(q, qdot, &H_pose_act, &H_vel_act); | ||
| expect = (Vector(12) << 00.613943126, 1.48218982, -0.613943126, 1.1609828, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please comment where you got these numbers from? And please mark this as a regression test. |
||
| 0.706727485, -0.547039678, 0, -0.141421356237309, 0, | ||
| -0.070710678118655, 0.070710678118655, -0.1000) | ||
| .finished(); | ||
| H_pose_exp = numericalDerivative11( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use |
||
| std::function<Vector(const Vector2&)>( | ||
| std::bind(&WorkspacePoseVelocityPrior::evaluateError, factor, | ||
| std::placeholders::_1, qdot, nullptr, nullptr)), | ||
| q, 1e-6); | ||
|
|
||
| H_vel_exp = numericalDerivative11( | ||
| std::function<Vector(const Vector2&)>( | ||
| std::bind(&WorkspacePoseVelocityPrior::evaluateError, factor, q, | ||
| std::placeholders::_1, nullptr, nullptr)), | ||
| qdot, 1e-6); | ||
| EXPECT(assert_equal(expect, actual, 1e-6)); | ||
| EXPECT(assert_equal(H_pose_exp, H_pose_act, 1e-6)); | ||
| EXPECT(assert_equal(H_vel_exp, H_vel_act, 1e-6)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assertions should follow immediately after the computation so that the code can fail early without doing extra computation. In this case, the first assert_equal should be right after the |
||
| } | ||
|
|
||
| /* ************************************************************************** */ | ||
| TEST(WorkspacePoseVelocityPrior, optimization) { | ||
| noiseModel::Gaussian::shared_ptr cost_model = | ||
| noiseModel::Isotropic::Sigma(12, 0.1); | ||
|
|
||
| Vector a = (Vector(2) << 1, 1).finished(); | ||
| Vector alpha = (Vector(2) << 0, 0).finished(); | ||
| Vector d = (Vector(2) << 0, 0).finished(); | ||
| Arm arm = Arm(2, a, alpha, d); | ||
| Pose3 des_pose = Pose3(Rot3(), Point3(2, 0, 0)); | ||
| Vector6 des_vel = Vector6(0, 0, 0, 0, 0, 0); | ||
| Key qkey = Symbol('x', 0); | ||
| Key qdotkey = Symbol('v', 0); | ||
| Vector q = (Vector(2) << 0, 0).finished(); | ||
| Vector qdot = (Vector(2) << 0, 0).finished(); | ||
| Vector qinit = (Vector(2) << M_PI / 2, M_PI / 2).finished(); | ||
| Vector qdotinit = (Vector(2) << 0.1, 0.1).finished(); | ||
|
|
||
| NonlinearFactorGraph graph; | ||
| graph.add(WorkspacePoseVelocityPrior(qkey, qdotkey, cost_model, arm, des_pose, | ||
| des_vel)); | ||
| Values init_values; | ||
| init_values.insert(qkey, qinit); | ||
| init_values.insert(qdotkey, qdotinit); | ||
|
|
||
| LevenbergMarquardtParams parameters; | ||
| parameters.setVerbosity("ERROR"); | ||
| parameters.setAbsoluteErrorTol(1e-12); | ||
| LevenbergMarquardtOptimizer optimizer(graph, init_values, parameters); | ||
| optimizer.optimize(); | ||
| Values results = optimizer.values(); | ||
|
|
||
| EXPECT_DOUBLES_EQUAL(0, graph.error(results), 1e-3); | ||
| EXPECT(assert_equal(q, results.at<Vector>(qkey), 1e-3)); | ||
| EXPECT(assert_equal(qdot, results.at<Vector>(qdotkey), 1e-3)); | ||
| } | ||
|
|
||
| /* ************************************************************************** */ | ||
| /* main function */ | ||
| int main() { | ||
| TestResult tr; | ||
| return TestRegistry::runAllTests(tr); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.