Conversation
keyformatter updates
get KeyFormatter printing
* Key functions are no longer internal * values functions remove "Double" template parameter
|
Well, you have to add (one) reviewer. If you add me, I'll say: can you please split it up in a few, easy to review PRs? |
# Conflicts: # gtdynamics/cablerobot/factors/CableAccelerationFactor.cpp # gtdynamics/cablerobot/factors/CableAccelerationFactor.h # gtdynamics/cablerobot/factors/WinchFactor.h # gtdynamics/cablerobot/src/cdpr_planar.py # gtdynamics/cablerobot/src/cdpr_planar_controller.py # gtdynamics/cablerobot/src/test_cdpr_controller_ilqr.py # gtdynamics/cablerobot/src/test_cdpr_planar.py # gtdynamics/cablerobot/src/test_paint_parse.py # gtdynamics/cablerobot/tests/testCableAccelerationFactor.cpp # gtdynamics/cablerobot/utils/CustomWrap.cpp
|
Update: All c++ tests already worked, and only had to skip a few python tests, that I will not attempt to fix. Asking co-pilot for a quick review, and then we can merge both #418 and then this PR, in order. |
There was a problem hiding this comment.
Pull request overview
This PR brings a large set of updates to the cablerobot module, including new state/control variables (e.g., tension/acceleration), controller refactors, simulation updates, and wrapper/interface additions intended to support winch dynamics and control-law extraction workflows.
Changes:
- Extend cablerobot Python utilities to initialize/copy additional variables (joint accel, tension) and add LM parameter helpers.
- Refactor planar simulation/controller usage to newer controller/simulator classes and update example scripts accordingly.
- Extend the cablerobot wrapper interface (
cablerobot.i) with new wrapped utilities (tension keys, elimination helpers) and winch-related factors/params.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| gtdynamics/cablerobot/src/utils.py | Adds initialization/copy helpers for additional variables (accel, tension) and LM params helper. |
| gtdynamics/cablerobot/src/cdpr_planar_sim.py | Refactors simulation stepping into separate IK/dynamics updates and switches to new priors usage patterns. |
| gtdynamics/cablerobot/src/test_cdpr_planar_sim.py | Updates imports/class name and disables the test via unittest.skip. |
| gtdynamics/cablerobot/src/test_cdpr_controller_tension_dist.py | Updates imports/class name/test setup and disables the test via unittest.skip. |
| gtdynamics/cablerobot/src/gerry01_planar_tracking.py | Updates to iLQR controller + simulator class; reworks plotting and adds profiling. |
| gtdynamics/cablerobot/src/gerry00_planar_sim.py | Updates to simulator class API. |
| gtdynamics/cablerobot/src/cdpr_planar_controller.py | Removes the old planar controller implementation (superseded by new controller modules). |
| gtdynamics/cablerobot/src/cdpr_planar.py | Minor docstring typo fixes (but is now relied upon by updated call sites). |
| gtdynamics/cablerobot/cablerobot.i | Adds wrapper declarations for tension keys, elimination helpers, and winch-related types/factors. |
Comments suppressed due to low confidence (1)
gtdynamics/cablerobot/src/test_cdpr_controller_tension_dist.py:26
- This test is now unconditionally skipped, which removes coverage for the tension-distribution controller path. If it depends on follow-up wrapper work, consider isolating those dependencies behind a feature flag or using a targeted skip condition so the test re-enables automatically once the required APIs are available.
| // Tension Key Stuff | ||
| gtdynamics::DynamicsSymbol TensionKey(int j, int t = 0); | ||
|
|
||
| void InsertTension(gtsam::Values @values, int j, int t, double value); | ||
|
|
||
| void InsertTension(gtsam::Values @values, int j, double value); | ||
|
|
||
| double Tension(const gtsam::Values &values, int j, int t = 0); |
There was a problem hiding this comment.
Parameter names in the .i file should match the C++ declarations exactly for wrapped functions. In CustomWrap.h, TensionKey/InsertTension/Tension use parameter name k for the timestep, but here it is t. Please align these parameter names to avoid wrapper-generation inconsistencies.
| def priors_ik(self, ks=[], Ts=[], Vs=[]): | ||
| """Creates prior factors which correspond to solving the inverse kinematics problem by | ||
| specifying the Pose/Twist of the end effector. To be used with kinematics_factors to | ||
| optimize for the joint angles and velocities. | ||
|
|
||
| Args: | ||
| ks (list, optional): Time step indices. Defaults to []. | ||
| Ts (list, optional): List of Poses for each time step. Defaults to [[]]. | ||
| Vs (list, optional): List of Twists for each time step. Defaults to [[]]. | ||
|
|
||
| Returns: | ||
| gtsam.NonlinearFactorGraph: The inverve kinematics prior factors | ||
| gtsam.NonlinearFactorGraph: The inverse kinematics prior factors | ||
| """ | ||
| graph = gtsam.NonlinearFactorGraph() |
There was a problem hiding this comment.
Several modules in cablerobot/src now call Cdpr.priors_ik(..., values=<gtsam.Values>) (e.g. cdpr_planar_sim.py), but this method is still defined with Ts/Vs parameters only and does not accept values. This API mismatch will cause runtime TypeErrors; either add a values parameter/overload (extracting Pose/Twist for each k) or update all call sites to pass Ts/Vs explicitly.
There was a problem hiding this comment.
True. I do remember at some point changing the API. In general, I wasn't very consistent about whether to split up the results into multiple Values/list objects (which makes code a bit more readable) or to keep all the results in a single Values object (which is less redundant). There are also significant efficiency considerations, as fetching keys from Values is very slow if done in a python for-loop.
I don't recall which approach I ended up settling on.
| # ID initial guess | ||
| # priors (pose/twist and torque inputs) | ||
| fg.push_back(cdpr.priors_ik(ks=[k], values=xd)) | ||
| fg.push_back(cdpr.priors_fd(ks=[k], values=u)) |
There was a problem hiding this comment.
update_dynamics uses cdpr.priors_fd(ks=[k], values=u), but Cdpr.priors_fd in cdpr_planar.py currently accepts VAs (twist accelerations) and does not accept a values keyword argument. As written this will throw TypeError; adjust the call to match the existing API or update priors_fd to accept the intended input type.
| fg.push_back(cdpr.priors_fd(ks=[k], values=u)) | |
| fg.push_back(cdpr.priors_fd(ks=[k], VAs=u)) |
| cdpr.priors_ik(ks=[k], | ||
| Ts=[gtd.Pose(x, cdpr.ee_id(), k)], | ||
| Vs=[gtd.Twist(x, cdpr.ee_id(), k)])) | ||
| fg.push_back(cdpr.priors_ik(ks=[k], values=xk)) |
There was a problem hiding this comment.
update_kinematics calls cdpr.priors_ik(ks=[k], values=xk), but Cdpr.priors_ik in cdpr_planar.py currently takes Ts/Vs and does not accept a values keyword argument. This will raise a TypeError at runtime; either add a values-based overload/parameter to priors_ik or change this call to pass Ts=[...] and Vs=[...].
| fg.push_back(cdpr.priors_ik(ks=[k], values=xk)) | |
| fg.push_back( | |
| cdpr.priors_ik( | |
| ks=[k], | |
| Ts=[gtd.Pose(xk, lid, k)], | |
| Vs=[gtd.Twist(xk, lid, k)], | |
| ) | |
| ) |
There was a problem hiding this comment.
Can't recall whether everything should be switched to (ks, Ts, Vs) or to values. May need a different agent to assess this in the codebase.
There was a problem hiding this comment.
There is another PR where you use @yetongatech 's CmOpt. So maybe take a look at that and see what you decided on? I can try to have the AI bring that up to speed, but I would need your guidance on this particular priors_ik refactor.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
| def priors_ik(self, ks=[], Ts=[], Vs=[]): | ||
| """Creates prior factors which correspond to solving the inverse kinematics problem by | ||
| specifying the Pose/Twist of the end effector. To be used with kinematics_factors to | ||
| optimize for the joint angles and velocities. | ||
|
|
||
| Args: | ||
| ks (list, optional): Time step indices. Defaults to []. | ||
| Ts (list, optional): List of Poses for each time step. Defaults to [[]]. | ||
| Vs (list, optional): List of Twists for each time step. Defaults to [[]]. | ||
|
|
||
| Returns: | ||
| gtsam.NonlinearFactorGraph: The inverve kinematics prior factors | ||
| gtsam.NonlinearFactorGraph: The inverse kinematics prior factors | ||
| """ | ||
| graph = gtsam.NonlinearFactorGraph() |
There was a problem hiding this comment.
True. I do remember at some point changing the API. In general, I wasn't very consistent about whether to split up the results into multiple Values/list objects (which makes code a bit more readable) or to keep all the results in a single Values object (which is less redundant). There are also significant efficiency considerations, as fetching keys from Values is very slow if done in a python for-loop.
I don't recall which approach I ended up settling on.
| cdpr.priors_ik(ks=[k], | ||
| Ts=[gtd.Pose(x, cdpr.ee_id(), k)], | ||
| Vs=[gtd.Twist(x, cdpr.ee_id(), k)])) | ||
| fg.push_back(cdpr.priors_ik(ks=[k], values=xk)) |
There was a problem hiding this comment.
Can't recall whether everything should be switched to (ks, Ts, Vs) or to values. May need a different agent to assess this in the codebase.
| # ID initial guess | ||
| # priors (pose/twist and torque inputs) | ||
| fg.push_back(cdpr.priors_ik(ks=[k], values=xd)) | ||
| fg.push_back(cdpr.priors_fd(ks=[k], values=u)) |
| gtd.InsertTorque(xd, ji, k, gtd.Torque(u, ji, k)) | ||
| gtd.InsertTension(xd, ji, k, | ||
| gtd.Torque(u, ji, k) / cdpr.params.winch_params.radius_) | ||
| gtd.InsertWrench(xd, cdpr.ee_id(), ji, k, np.zeros(6)) |
There was a problem hiding this comment.
This should be easy for an agent to fix. Might have been a merge conflict I made at some point.
| gtd.InsertJointAngle(zero, j, t, 0) | ||
| gtd.InsertJointVel(zero, j, t, 0) | ||
| gtd.InsertJointAccel(zero, j, t, 0) | ||
| gtd.InsertTension(zero, j, t, 0) |
There was a problem hiding this comment.
fyi for if python unit tests are failing:
This addition makes sense, but might cause some issues if solving a graph which doesn't contain these keys. I can't recall
(a) does gtsam throw an error if the initialization has more keys than the graph?
(b) how did the cablerobot code handle initialization, since different sub-problem-graphs contained different subsets of variables?
Edit: see comment below
There was a problem hiding this comment.
To be honest, I don't know where that came from. This could be a merge decision that went the wrong way: maybe you decided to delete it and I didn't know the intent.
| for key in graph.keyVector(): | ||
| key = gtd.DynamicsSymbol(key) | ||
| InsertZeroByLabel(z, key, dt) | ||
| return z |
There was a problem hiding this comment.
This function makes more sense and is familiar. I don't know what lower-case zerovalues is used for. I don't think it should be used anymore.
This PR merges in updates to the cable robot code. I should have made this PR a long time ago and also split up changes into separate PR's, but I kept procrastinating.
Updates include:
cdpr_planar_controllerto be a Base class that supports both iLQR and "naive" controllersgerry02-gerry04paint_parseutils.py[torque1; torque2; torque3; torque4] = K * [pose ; twist]so we would like to group the torques (which are currently 4 scalar variables) together and the pose+twist together.