Joint refactor#414
Conversation
| // TODO(dellaert): use formula `pMj_ * screw_around_Z * jMc_`. | ||
| gtsam::Matrix6 exp_H_screw; | ||
| const Pose3 exp = Pose3::Expmap(screw, pTc_H_q ? &exp_H_screw : 0); | ||
| const Pose3 exp = Pose3::Expmap(screw); |
There was a problem hiding this comment.
Important simplification: exp_H_screw is expensive
| *pTc_H_q = cScrewAxis_; | ||
| } | ||
| return pMc() * exp; // Note: derivative of compose in exp is identity. | ||
| return pMc_ * exp; // Note: derivative of compose in exp is identity. |
There was a problem hiding this comment.
Avoids 4x4 matrixmul in inner loop.
There was a problem hiding this comment.
Pull request overview
Refactors gtdynamics::Joint’s internal transform bookkeeping and Jacobian computation, updating C++/SWIG/Python call sites accordingly and adding a focused Jacobian test.
Changes:
- Rename/flip the stored “rest” transform from
jMptopMj, and add a cachedpMctransform. - Simplify
Joint::parentTchildJacobian computation and add direct numerical-vs-analytic tests. - Update SWIG interface and Python notebook usage for the new API (
pMj()/pMc()).
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
gtdynamics/universal_robot/Joint.h |
Renames jMp→pMj, adds cached pMc, updates equality and Boost serialization fields. |
gtdynamics/universal_robot/Joint.cpp |
Updates constructor transform computation, simplifies parentTchild Jacobian path, uses cached pMc_. |
gtdynamics.i |
Updates wrapped API to pMj() and returns pMc() by const reference. |
tests/testJoint.cpp |
Adds numerical Jacobian checks for parentTchild (and axis equality assertions). |
tests/testRevoluteJoint.cpp |
Simplifies using declarations and updates serialization helper namespace usage. |
python/tests/chain.ipynb |
Switches from jMp().inverse() to pMj() usage. |
python/notebooks/cmopt_benchmark_dashboard.ipynb |
Notebook re-execution/output updates (benchmark timings/counts). |
| pMj_(parent_link.lock()->bMcom().between(bTj)), | ||
| jMc_(bTj.between(child_link.lock()->bMcom())), | ||
| pMc_(pMj_ * jMc_), | ||
| pScrewAxis_(-pMj_.AdjointMap() * jScrewAxis), // Negative sign ??? |
There was a problem hiding this comment.
The constructor leaves an unresolved question in a code comment (// Negative sign ???). This reads like uncertainty about the correctness of the sign on the screw-axis transform; please either remove the comment and keep the sign, or replace it with a concrete justification (e.g., which adjoint/coordinate convention requires the minus sign). If the sign is actually wrong, this will silently flip joint directions in downstream kinematics/dynamics.
| pScrewAxis_(-pMj_.AdjointMap() * jScrewAxis), // Negative sign ??? | |
| /// pScrewAxis_ is the joint screw axis expressed in the parent COM frame. | |
| /// The negative sign reflects that the joint motion is defined as the child's | |
| /// motion relative to the parent, while pScrewAxis_ is stored as a twist of | |
| /// the parent frame under the chosen adjoint/twist convention. | |
| pScrewAxis_(-pMj_.AdjointMap() * jScrewAxis), |
|
@copilot open a new pull request to apply changes based on the comments in this thread |
Co-authored-by: dellaert <10515273+dellaert@users.noreply.github.com>
Co-authored-by: dellaert <10515273+dellaert@users.noreply.github.com>
Address code review feedback: clarify screw axis sign and fix pMc_ serialization
|
@varunagrawal I added a few more optimizations in this PR |
| gtsam::Matrix6 H_twistdt; | ||
| auto pose_t1_hat = predictPose(pose_t0, twistdt, H_pose_t0, H_twistdt); | ||
| gtsam::Vector6 error = pose_t1.logmap(pose_t1_hat); | ||
| gtsam::Vector error = pose_t1.logmap(pose_t1_hat); |
There was a problem hiding this comment.
What was the purpose of this? I actually liked the Vector6 since it specified the dimension within the type.
There was a problem hiding this comment.
Error is returned by RVO, might as well immediately allocate right type, which is Vector
There was a problem hiding this comment.
Won't the compiler do that for us? Might as well make it easier for the developer and be self-documenting.
There was a problem hiding this comment.
I don't think so. Vector 6 is stack allocated, Vector is heap allocated. I think it will just lead to a copy.
There was a problem hiding this comment.
I'm trying to be helpful as a reviewer by asking clarifying questions.
There's no need to be condescending.
There was a problem hiding this comment.
RVO is literally a Google search away. I don't know why you would not search for it and make me type the answer instead.
There was a problem hiding this comment.
Which is what I did and why I deleted the question before you could respond.
| joint_->poseOf(joint_->child(), wTp, measured_joint_coordinate_, H_wTp); | ||
|
|
||
| gtsam::Vector6 error = wTc.logmap(wTc_hat, H_wTc, H_wTp ? &H : 0); | ||
| gtsam::Vector error = wTc.logmap(wTc_hat, H_wTc, H_wTp ? &H : 0); |
There was a problem hiding this comment.
Same comment about type here.
| * @param new_name The new name of the joint. | ||
| */ | ||
| void rename(const std::string& new_name) {name_ = new_name; } | ||
| void rename(const std::string &new_name) { name_ = new_name; } |
There was a problem hiding this comment.
You probably need to check your formatter settings. In the Google C++ Style Guide (which you recommended) the ampersand is on the type, not the name.
There was a problem hiding this comment.
I don’t reformat files on PRs with single line changes to avoid adding a lot of unrelated diffs
There was a problem hiding this comment.
This line has been reformatted though? Asking because when someone runs a formatter later, this will add a lot of distracting changes.
| friend class boost::serialization::access; | ||
| template <class ARCHIVE> | ||
| void serialize(ARCHIVE &ar, const unsigned int /*version*/) { | ||
| void save(ARCHIVE &ar, const unsigned int /*version*/) const { |
There was a problem hiding this comment.
Shouldn't this be serialize since GTSAM's save and load will call this?
There was a problem hiding this comment.
I am not sure I understand what is going on here...
There was a problem hiding this comment.
Save/load is an alternative pipeline- this is to avoid saving pMc_
| const double &torque, | ||
| gtsam::OptionalMatrixType H_torque = nullptr) const override { | ||
| gtsam::Vector error = (gtsam::Vector(1) << torque).finished(); | ||
| gtsam::Vector error(1); |
There was a problem hiding this comment.
You can instead define this via:
gtsam::Vector errror {{torque}};I have verified this on my local machine.
|
Appreciate the comments - but none of them rise to doing another CI cycle. Will merge if you’re ok. |
|
Also, @varunagrawal , did you see question in PR comment? |
@varunagrawal this does change serialization. Is that a problem for you? Don't think it should matter (to anyone) as we always read from URDFs anyway.