Repository navigation
Conversation
Added support for stacked numpy arrays in baseposelist.py.
… error Added support for SE3 constructor with (N, 4, 4) NumPy array.
Add unit test for SE3 constructor with stacked array input.
…ating a second one axes_logic reuses the current axes when the current figure has axes, but when the current figure had none, as after a bare plt.figure(), it called plt.figure() again. Every "new plot" idiom (plt.figure() followed by a plot_xxx call) therefore left an empty figure behind, most visible with the ipympl backend where figures stay open in notebooks. Put the axes in the empty current figure instead. new=True still always makes a new figure, a dimension mismatch still makes a new figure, and a current figure that has axes is reused as before. Add direct tests of axes_logic (there were none): the existing behaviour, and the empty-current-figure cases. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: 李永祺 <doribelove@gmail.com>
Signed-off-by: 李永祺 <doribelove@gmail.com>
The docstring was indented by an extra four spaces and a stray 'from typing import TYPE_CHECKING' line ended the runblock early, which would render incorrectly in the docs. Restore the docstring formatting to match the rest of the module; the lazy SymPy import is unchanged.
The shape guard added with the stacked-array support rejected every array whose shape differed from the class's internal value shape when check=False. That broke accepted equivalent forms: Twist3 from a 4x4 SE(3)/se(3) matrix, Twist2 from a 3x3 SE(2)/se(2) matrix, and Quaternion from a non-4-vector array, all of which the class _import methods deliberately accept unchecked. Only reject when a matrix pose class (SE3, SO3, SE2, SO2) gets a 3D array whose per-matrix size is wrong: such an array can only be read as a stack, so the mismatch is never a valid pose, whatever check is. Single 2D arrays keep their historical check=False behavior.
Signed-off-by: 李永祺 <doribelove@gmail.com>
Every UnitQuaternion has a non-negative scalar part by construction (qunit()), and interp1 always interpolates from the identity quaternion, whose dot product with any unit quaternion is just that quaternion's own scalar part. The negative-dot-product condition `shortest` checks for to detect "the long way round" can therefore never occur here -- confirmed empirically (2000 random compositions, plus explicit UnitQuaternion([-1,0,0,0]) construction, all canonicalize to non-negative scalar part). Drops the dead branch, warns on shortest=True, documents why in a docstring note, and pins the no-op behavior (identical results for True/False, warns only when True) with a regression test.
Twist3.__mul__ raised a hard ValueError for any right operand it didn't directly recognize, instead of returning NotImplemented -- so Python never got the chance to fall back to right.__rmul__(left). This made Twist3 * SpatialVelocity/Acceleration/Force/Momentum unconditionally fail, even though SpatialVector.__rmul__ explicitly documents supporting Twist3 alongside SE3. Found while independently verifying #207 (SpatialForce/Momentum coadjoint fix): that PR's Twist3 code path is correct but was untestable through normal `*` syntax because of this bug.
Add a test to ensure scipy is not loaded when importing spatialmath.
Ad() was self.SE3().Ad() -- constructs a full validated SE3 object just to immediately extract its array and discard the object. Computes the same result directly (trexp then tr2adjoint, skipping the SE3 constructor/validation overhead): bit-identical output, ~1.4x faster. No existing test covered Ad() at all; added one first (hand-verified pure-rotation and pure-translation cases, plus a cross-check against SE3.Ad() over 20 random transforms) and confirmed it passes unchanged against both the old and new implementation.
…trings Follow-up to the twist-sequence broadcasting change. A search for cut/paste errors between Twist2 and Twist3 turned up some real bugs as well as text: - isprismatic/isrevolute raised AttributeError on a sequence because they read .w/.v from the raw ndarrays in .data instead of the Twist elements. - Twist2.__rmul had no trailing underscores so it was never called, and ``2 * Twist2`` silently fell through to UserList repetition. - Twist3.__rmul__ used right.S, which is a list for a sequence, so scalar * Twist3 failed for sequences. - Twist3.Rand used yrange[0] as the lower bound of the z range. Docstrings: Twist2.SE2 said it returned SE3 and pointed at Twist3.exp (and its degree-mode message named Twist3.exp); Twist2.__init__ said it built a prismatic twist and swapped the moment/direction sizes; Twist2.isvalid described a 6-vector/4x4; UnitRevolute said prismatic; Twist3.Rand described SE3.Rand; Rx/Ry/Rz called their results SE(3)/SO(3) rotations; the [omega, v] ordering note contradicted the [v, omega] data layout; exp() documented a default of None and left a literal unterminated; the ``runblock:`` directives in __str__/__repr__ had a single colon (and their examples would not have run once fixed). SE2.Rand's example used SE3. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A twist is used both as the log of a pose (RVC, Modern Robotics) and as a velocity (ROS Twist). They share the vector, the [v, w] layout and the algebra, but nothing in the docstrings said so. Say so, point to SpatialVelocity as the typed counterpart, and note which properties are invariant to scaling the twist and which are not. Twist2 had no class docstring, only __init__, so give it one. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…ib block isnotebook() lived inside graphics.py's matplotlib try-block, so it vanished when matplotlib was missing, and it reported False for Google Colab and JupyterLite. RTB, MVTB and bdsim each grew their own copy as a result. Add environment(), returning "terminal", "ipython", "jupyter", "colab" or "jupyterlite", in a new matplotlib-free module, and make isnotebook() a thin wrapper that is True for jupyter, colab and jupyterlite. smb.isnotebook is still exported. Tests use a faked get_ipython/sys.modules/sys.platform. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Avoids a textual conflict with other PRs that add tests after the line distance tests, and restores the executable bit on the test file, which runs as a script.
The package is pure Python, so numpy is not needed to build it, and numpy has deprecated oldest-supported-numpy. Build tools that do not install arbitrary build requirements (for example rules_py's uv sdist builder) fail on it.
…copied docstrings; document twist usages (builds on #248)
…ses (SE3, SO3, SE2, SO2)
… instead of creating a second one
…of the matplotlib block
taughz
force-pushed
the
integration/2026-11
branch
from
November 5, 2026 15:05
81c99fb to
bcbec7b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Do not merge this PR. It is a hub for integration testing the open PR backlog against internal RAI software. The branch stages the PRs listed below, one
--no-ffmerge commit per PR in merge order, so they can be tested together. Once that passes, the individual PRs are approved and merged tomasterin this order (ticking them off here), and this hub is closed.The branch is rebuilt (force-pushed) whenever a contained PR changes or lands on
master. Do not rebase it: that would flatten the per-PR merge commits.Contained PRs (merge order)
High-priority PRs first, then the rest roughly oldest first, with related PRs kept adjacent. Simulated merges show no textual conflicts in this order.