Changelog¶
Unreleased¶
contactTestreleases the GIL — parallel collision checking across cores —DiscreteContactManager.contactTestandContinuousContactManager.contactTestnow bind withnb::call_guard<nb::gil_scoped_release>(), mirroring the motion planners'solve()guards. Without it a Python worker thread sweeping a trajectory for collisions only time-shared the GIL with the main thread (concurrency, not parallelism — the sweep didn't get faster and contended with the UI); with it, sweeping on per-thread cloned managers scales near-linearly — measured 1.95× on 2 threads (10-core machine) against a 0.99× pure-Python control that rules out a measurement artifact. Enables off-main-thread, sharded collision scans of a whole program (#122).- Plugin-backed objects keep their Environment alive — fixes the gh-72 SIGSEGV lottery —
getKinematicGroup/getJointGroup/getDiscreteContactManager/getContinuousContactManagernow bind withnb::keep_alive<0, 1>. These objects are plugin-created (OPW/KDL/UR kinematics, bullet/fcl collision factories) and their vtables live in dylibs owned by the Environment's plugin loader; when Python destroyed the Environment first (interpreter-teardown dict order, pytest GC), the loader dlclosed the plugin dylibs and the survivors' destructors virtual-called into unmapped pages. Whether a given script crashed was pure destruction-order luck — the reported "calcJacobiansegfaults under pytest but works in plain Python" was this lottery, not the jacobian path (lldb forensics: dangling vptr pinned inside unloadedlibtesseract_kinematics_opw.dylib) ([#72]). - Linux wheels: libstdc++ no longer bundled — fixes dual-copy heap corruption — the ldd-closure bundling swept the conda env's gcc-14
libstdc++.so.6into every wheel; numpy/scipy load the system copy, the loader unifiesSTB_GNU_UNIQUElocale statics across the two, andstd::regexinsidePropertyTree::rebuildAutoValidatorsfreed a stack address duringEnvironment.init(SIGSEGV/double free or corruption— detection-dependent UB, so the pytest suite corrupted silently). The gcc runtime (libstdc++,libgcc_s) is now excluded from bundling, the GH #35RTLD_GLOBALpreload is removed (its "two copies coexist safely" premise was falsified), and a test-wheel CI guard asserts ships-no-copy / one-copy-mapped / numpy-firstenv.initclean. Wheels now require a gcc-13+ era system or conda libstdc++ (ubuntu 24.04+, debian 13+); older distros fail loudly at import. Full forensics:docs/developer/linux-wheels.md([#119]). - Basic Descartes example —
descartes_raster_c_api_example.py, low-level port of upstreammotion_planners/examples/raster_example.cpp: a 3-pass raster program solved byDescartesMotionPlannerDdirectly (no TaskComposer) with TrajOpt refinement chained on the result;CompositeInstructiongains the full C++ constructor (profile, manipulator_info, order) so UNORDERED transition composites are constructible from Python ([#87]). - Descartes woven into the high-level planning API — new
create_descartes_pipeline_profiles()for the standaloneDescartesF/D(NPC)Pipelinefamily, andcreate_descartes_default_profiles()grows the 0.35 knob surface: tool-axis rotation sampling for axis-symmetric processes (sample_axis/sample_resolution/sample_min/sample_max→target_pose_fixed=False),ik_solveroverride,use_redundant_joint_solutions, andmove_profile=injection of custom (Python-subclassable, #83)DescartesMoveProfileDinstances — mutually exclusive with the knobs, fails loud ([#85]). - Lowlevel planning example: TrajOpt profiles reach the solver —
tesseract_planning_lowlevel_c_api_example.pyadded its TrajOpt plan/composite profiles to the OMPL dictionary while handing the solver an emptytrajopt_profiles; TrajOpt silently planned on fallback defaults ([#115]). get_task_composer_config_path()resolves like the runtime — returns the@PLUGIN_PATH@-patched config that_configure_environment()publishes viaTESSERACT_TASK_COMPOSER_CONFIG_FILE(env var → bundled data → conda share) instead of unconditionally returning the bundled-only path, which doesn't exist in dev envs and was unpatched in wheels; raises the newTaskComposerConfigNotFoundErrorwhen nothing resolves; the hand-rolled fallback chains in the task composer tests,TaskComposer.from_config, andscripts/generate_pipeline_dotgraphs.pynow delegate to it ([#110]).- ruff enforces the py39 floor —
FA102added to lint select so PEP 604 unions withoutfrom __future__ import annotationsfail the hooks; withtarget-version = "py39"(rejects 3.10+ syntax) this turns 3.9 compatibility from convention into a gate ([#92]).
0.35.0.4 - 2026-06-08 — conda-forge C++ deps + OSQP tunability + Linux libstdc++ preload + CI hardening¶
- OSQP solver settings exposed —
OSQPEigenSolvergains seven tunable setters (setPolish,setWarmStart,setAdaptiveRho,setMaxIteration,setAbsoluteTolerance,setRelativeTolerance,setVerbosity) andTrajOptIfoptOSQPSolverProfilegainssetAdaptiveRhoInterval, enabling iteration-based (deterministic) rho adaptation for reproducible SQP solves; fixes dangling-pointer segfault ingetJacobian()viarv_policy::reference_internalongetVar/getNode/getNodes(0f40048, c984044, c083f5e, #103). - OMPL RNG determinism —
RNG_setSeed/RNG_getSeedbound intesseract_motion_planners_ompl;conftest.pyauto-reseeds per test for xdist-safe reproducibility; single-planner +optimize=Falserecipe documented as the only guaranteeable determinism contract (parallel-plan best-of-N races even with seeded samplers); Windows determinism test dropped — conda-forgeompl.libembeds a separateRNGSeedGeneratorcopy per DLL so seeding the extension can't reach the planner (a0f49c6, 5f4776e, 31c7541, #103). - conda-forge C++ deps — C++ stack migrated from colcon workspace build to conda-forge prebuilts;
pixi install && pixi run buildreplacespixi run build-cpp/ colcon;pixi.lockv7 with eigen-abi-taggedorocos-kdl _2ending heap corruption in all KDL paths;locked:true+ pinnedpixi-versionin CI so stale-lock drift fails loud; build-dir cache keyed onpixi.lockhash; Python 3.9 feature env added for Rhino 8 (b6a14c4, 3c80a25, 6210a99, 0455e34). - Linux libstdc++ preload — bundled gcc-14
libstdc++loadedRTLD_GLOBALas the first act of__init__wins the SONAME race before numpy/scipy can pull in the system copy on Ubuntu 22.04 and older; gated onCONDA_PREFIXabsence to avoid double-loading inside pixi/conda envs (#35, ee83dc8, 7715422). Environment.setStateinput validation — unknown or non-active (fixed/mimic) joint names now raiseValueErrorwith a clear message instead of silently dereferencing unmapped entries and crashing withSIGSEGV; all three entry points covered (dict, names+values,setStateByNamesAndValues) (#43, ca620d3).SceneGraphtype registration in URDF module —_tesseract_urdfnow imports_tesseract_scene_graphat module load so the return type ofparseURDFFileis always registered; was masked by full-suite imports, exposed by the new minimal-import ABI canary (f944293).- CI hardening — Windows test-wheel now runs the full suite (kinematics + examples, benchmarks-only exclusion); macOS nanobind build directory cached to halve warm builds; ABI canary (install wheel into pixi env → kinematics smoke-test) on Linux and macOS build jobs catches dep-ABI rot in ~30 s instead of as scattered segfaults in test-wheel; duplicate CI env block merged (e60f272, b29c37a, 04a812f, 6210a99, 607b4b9).
- Dotgraph polish —
TaskComposerpipeline diagrams woven into docs;clean_dot_labelsstrips dump-debug fields for legibility; contract test + type annotations (4aa5efb, 57537da, 1bfb4c3).
0.35.0.3 - 2026-06-05 — complete wheel matrix for the 0.35.0.2 content¶
Reissue of 0.35.0.2 with the full wheel set actually published. In 0.35.0.2 a dirty CI build tree made setuptools_scm stamp a PEP 440 local segment (+d<date>) onto some wheels; PyPI rejects those with HTTP 400, and the non-idempotent publish step aborted mid-upload — so macOS (all) and Linux x86_64 (cp39/cp311) wheels never landed. 0.35.0.2 is yanked. Identical bindings to 0.35.0.2 — no API changes (49f1aa9).
- Release pipeline hardened —
setuptools_scmlocal_scheme = "no-local-version"so a dirty tag build can't produce a PyPI-rejected local version;skip-existing: trueon all three publish workflows so re-runs fill gaps instead of 400-aborting; macOSfail-fast: falseso one flaky build can't cancel sibling wheels; plus a 3× retry on the macOSupload-artifactstep working around GitHub's long-standing arm64-runnerCreateArtifacttimeout (actions/upload-artifact#569, still open) that otherwise skips the entire macOS publish ~80% of the time (49f1aa9, 804d5b8). cp312-abi3support verified on all platforms — macOS and Windowstest-wheelnow install thecp312-abi3wheel on Python 3.13/3.14 (mirroring Linux;wheel != python), so the published 3.9–3.14 support matrix is verified in CI, not just asserted (14a4cea).
0.35.0.2 - 2026-06-04 — aarch64 / Jetson Linux wheels + collision manager bindings¶
Extends Linux wheel coverage to aarch64 (including NVIDIA Jetson), completes the contact-manager binding surface, and hardens the new ROS RPY decomposition against gimbal-lock edge cases (#97, 669f2da, f30014b).
aarch64/ NVIDIA Jetson Linux wheels — new GitHub Actions matrix entry plus Jetson build patches, built for Python 3.12+ onaarch64; Linux wheel CI standardised onpixi run build-cpp/build-wheel(#52, dc3f1df, 605dc4d, af7bc4e, #91, ba0510f, c897251, @Joelkang).- Collision manager bindings completed — remaining discrete/continuous contact-manager surface plus Descartes
MoveProfilecontact-manager config (#94, 9bfd6b1, 7a3b0e3, @Joelkang).
0.35.0.1 - 2026-05-29 — tesseract 0.35.0 upgrade + Eigen geometry suite + RAPID emitter¶
Major dependency bump to tesseract 0.35.0, a complete Eigen geometry binding surface with scalar-last quaternions as the project canon, a Pose that now is an Isometry3d, and a new ABB RAPID code emitter. (First wheel release of the 0.35 series; the project's setuptools_scm scheme requires four-component tags, so it is 0.35.0.1, not 0.35.0.)
- Complete Eigen geometry binding suite — fleshed-out
Vector3d/Vector4d/Matrix3d/Quaterniond/AngleAxisd/Isometry3dsurface, with scalar-last[qx, qy, qz, qw]Quaterniond.from_xyzwandQuaterniond.from_rpy/to_rpyZYX ROS RPY interop; float64 default precision centralised via EigenNumTraits(#76, 492ab7a, 544f7dd, 1d6f5c7, ef26fc9). - ABB RAPID code emitter for
tesseract_command_language(tesseract_robotics.emitters.rapid) (#75, 37f21b2). Octreegeometry bindings (plusoctomap::OcTree,OctreeSubType,PointCloud,createOctree) and the remainingtesseract_geometryutilities (isIdentical,extractVertices,toTriangleMesh) (#67, 4575aa9, @Joelkang).- Python-subclassable Descartes evaluators/sampler/profile for
tesseract_motion_planners_descartes— new bindings forDescartesStateD,DescartesStateSampleD,DescartesEdgeEvaluatorD,DescartesWaypointSamplerD,DescartesStateEvaluatorD, and a now-subclassableDescartesMoveProfileDlet users overridecreateWaypointSampler/createEdgeEvaluator/createStateEvaluatorfrom Python (#83, 620b228, @Joelkang). - Upgraded to tesseract 0.35.0 — deps bumped (
rosinstall→repos),MIGRATION.mdsed applied, namespace aliases added, resource URIs and dev paths updated for the 0.35 layout, wheel data dirtesseract_support→tesseract/support,kinematics_core_factories→kinematics_factories, descartestp::MoveInstructionPoly→tcl::MoveInstructionPoly(#86, 6710ccf, 422c5ea, 4e08a36). Posenow subclassesIsometry3d(tesseract_robotics.planning) — rotation math via Eigen, numpy-property facade dropped, factories collapsed to one name accepting both scalar-positional and arraylike call styles,Transformalias removed in favour of the single canonicalPose, stored-data accessors exposed as properties (#76, a202a45, caa3b19).- Scalar-last quaternions declared project canon —
[qx, qy, qz, qw];Quaterniond(w, x, y, z)literals migrated toQuaterniond.from_xyzw(0bd408d, f7b2fea). - README gains an examples section and a refreshed platform-support matrix (d7bde99, 8eed899).
KinematicsInformation.group_tcpsexposed to Python (tesseract_srdf) (#79, 52fdfba).TaskComposerNodeInfoContainerreturnsTaskComposerNodeInfo(#81, 106d162, @Joelkang).getSeed()exposed onCartesianWaypoint(#80, 0c57074, @Joelkang).- Viewer light color (#73, 3b4c545, @johnwason).
0.34.1.7 - 2026-05-09 — command_language I/O instructions + TaskComposer introspection¶
Python API surface expansion: tesseract_command_language gains its remaining I/O and pacing instruction types (Wait, Timer, SetAnalog, SetDigital, SetTool) — closing the gap that previously forced raster and pick-and-place pipelines through C++ or YAML — alongside TaskComposer DAG visualisation via GraphViz DOT output and TaskComposerDataStorage introspection helpers. Welcomes @seonixx (Simon White) as a new contributor.
- Remaining
tesseract_command_languageinstruction types bound:WaitInstruction,TimerInstruction,SetAnalogInstruction,SetDigitalInstruction,SetToolInstruction, with theirWaitInstructionType/TimerInstructionTypeenums andInstructionPoly_as_*cast helpers. Closes the I/O-and-pacing gap that previously forced raster/pick-and-place pipelines to be authored in C++ or YAML. Newtests/tesseract_command_language/test_command_language.pycovers construction, casting, andInstructionPolyround-tripping (#70, a4c26df, @Joelkang). - TaskComposer DAG visualisation —
getDotgraph()/saveDotgraph()overloads onTaskComposerNode, with an optionalTaskComposerNodeInfoContainerargument to highlight the executed path on a previously-run DAG. Emits GraphViz DOT for debugging otherwise-opaque planning pipelines (#63, e7c3a92, @Joelkang). TaskComposerDataStorageAnyPoly cast/wrap helpers —AnyPoly_wrap_TaskComposerDataStorageandAnyPoly_as_TaskComposerDataStorage, so DAG storage state can be inspected after each node from Python instead of only via C++ (#66, b30ed46, @Joelkang).TaskComposerDataStorage.getAllData()no-arg overload binding returning the full data map (#66, 990705f, @seonixx).DiscreteContactCheckTaskexposescontact_resultsthroughtask_infosdata_storage, with unit and integration test coverage (#66, 4fe07bf, 06178f0, @seonixx).- SimplePlanner and time-parameterization profiles now reachable via the public
tesseract_motion_planners_simpleandtesseract_time_parameterizationpackage paths instead of only the underscore-prefixed C++ extension modules. C++ binding-side registrations retired in favour of__init__.pyre-exports;test_constant_tcp.pyconsolidated intotest_time_parameterization.py(#62, d73e227, 30c8e9f, @Joelkang). InstructionPoly_as_CompositeInstructionre-exported fromtesseract_command_languagepackage init — was bound but not surfaced (#70, 110e1e0, @Joelkang).
0.34.1.6 - 2026-04-27 — PyPI README refresh¶
Same wheels as 0.34.1.5; recut so the published wheel's README metadata includes the Windows build badge alongside Linux and macOS on PyPI's project page.
- README badge row includes a Windows build badge (6656815).
0.34.1.5 - 2026-04-27 — Windows x64 wheels debut + Python profile bindings¶
First complete cross-platform PyPI release: Linux, macOS, and Windows wheels for Python 3.9–3.12. Closes the long-running #40 Windows wheels initiative (#58). Also ships a batch of profile-binding contributions from @Joelkang that had been queued in Unreleased.
- Windows x64 wheels published to PyPI via the new
wheels-windows.ymlworkflow. Mirrorswheels-{linux,macos}.yml; sources C++ deps from conda-forge via pixi; bundles plugin DLLs viadelvewheel repair --analyze-existing(f9c122d, 3e3a2e4). __init__.pyprepends the package dir andtesseract_robotics_nanobind.libs/toPATHon Windows — required becauseboost::dll's plainLoadLibraryignoresos.add_dll_directory(006ce38).- Cereal polymorphic types re-registered in the
tesseract_serializationbinding TU — MSVC instantiates the cereal registry per-DLL, so upstream's registrations don't reach the consumer.pydwithout re-registration (af88515). - New developer doc
docs/developer/windows-wheels.mdcapturing four Windows wheel packaging gotchas surfaced during the gh-40 diagnosis (fe5ad75). CompositeInstruction.push_backnow accepts aCompositeInstructionin addition to a plainInstruction, enabling nested composites (e.g. raster programs) to be built from Python the same way they are in C++ (#51, 6d17314, @Joelkang).- SimplePlanner profiles configurable from Python —
SimplePlannerCompositeProfileplus seven concrete move profiles (FixedSize,FixedSizeAssign,FixedSizeAssignNoIK,LVS,LVSNoIK,LVSAssign,LVSAssignNoIK), withProfileDictionary_addSimplePlannerMoveProfile/…CompositeProfilehelpers for registration (#54, e2bf837, @Joelkang). - task_composer planning-node profiles exposed through a new
tesseract_task_composer_planningmodule:ContactCheckProfile,FixStateBoundsProfile,FixStateCollisionProfile,KinematicLimitsCheckProfile,MinLengthProfile,ProfileSwitchProfile, andUpsampleTrajectoryProfile. Heavy TrajOpt-typed members onFixStateCollisionProfile(OSQP settings, SQP params, coeff data) are intentionally skipped — configure those via YAML or C++ (#56, 62cd2cd, @Joelkang). ConstantTCPSpeedParameterization(KDL-based, constant TCP-speed time parameterization) bound alongside itsConstantTCPSpeedCompositeProfile(#55, f4f981d, @Joelkang).- vcpkg-based
wheels-windows.ymlvariant (workflow_dispatch-only, never green) replaced by the conda-forge / pixi pipeline of the same name (3e3a2e4).
0.34.1.4 - 2026-04-27 [YANKED] — partial cross-platform release¶
Yanked. Linux and macOS wheels published successfully; Windows wheels built and tested but the publish job hit a PyPI Trusted Publisher configuration mismatch and didn't upload. Superseded by 0.34.1.5.
0.34.1.2 - 2026-04-23 — macOS arm64 stability¶
Follow-up to the macOS arm64 debut in 0.34.1.1, resolving a garbage-collection crash that surfaced in fresh virtual environments during motion planning.
- Dedupe versioned dylibs in the wheel — the actual root cause of the macOS GC crash (#48, 7f53185).
- Pin plugin dylibs on macOS to prevent a garbage-collection crash during motion planning (#48, 590343f).
- Restore the CI macOS test scope that had been narrowed as a workaround for #48 (#49, 07f8f9c).
0.34.1.1 - 2026-04-23 — macOS arm64 wheels debut¶
First PyPI-published macOS arm64 wheels, shipping via a dedicated wheels-macos.yml workflow parallel to the existing Linux x86_64 pipeline. Also introduces a Python trampoline for ConstraintSet, Python 3.9 compatibility for example modules, and installable example scripts.
- macOS arm64 wheels published to PyPI via a split, per-platform workflow (d80e689).
- Python trampoline for
ifopt.ConstraintSetso users can subclass it from Python for custom SQP constraints (361c60e). - Examples installable as console scripts (e.g.
tesseract_basic_cartesian_example) via[project.scripts](2c62952, @marip8). pixi run build-wheeltask for local wheel builds (e26df2a).- Non-benchmark tests fail loud instead of being silently skipped (a1d7607).
- Python 3.9 compatibility for example modules via
from __future__ import annotations(87ce68e).