openscvx 0.4.1.dev170__tar.gz → 0.4.1.dev172__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.gitignore +3 -0
- {openscvx-0.4.1.dev170/openscvx.egg-info → openscvx-0.4.1.dev172}/PKG-INFO +1 -1
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/07_lie.md +93 -0
- openscvx-0.4.1.dev172/examples/animations/7_dof_arm.py +225 -0
- openscvx-0.4.1.dev172/examples/animations/_camera.py +142 -0
- openscvx-0.4.1.dev172/examples/animations/_render.py +261 -0
- openscvx-0.4.1.dev172/examples/animations/_sensor_view.py +306 -0
- openscvx-0.4.1.dev172/examples/animations/dr_vp_polytope.py +180 -0
- openscvx-0.4.1.dev172/examples/animations/logo.py +154 -0
- openscvx-0.4.1.dev172/examples/animations/obstacle_avoidance_vmap.py +151 -0
- openscvx-0.4.1.dev172/examples/arm/7_dof_arm_collision.py +507 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/plotting_viser.py +138 -68
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/_version.py +3 -3
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/viser/animated.py +37 -12
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172/openscvx.egg-info}/PKG-INFO +1 -1
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx.egg-info/SOURCES.txt +8 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_examples.py +4 -2
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/assets/logo.svg +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/release-drafter.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/_docs.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/branch-name.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/docs.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/lint.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/nightly.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/release-drafter.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/release.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/tests-integration.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/.github/workflows/tests-unit.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/CONTRIBUTING.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/LICENSE +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/README.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/Foundations/constraint_reformulation.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/Foundations/control_parameterization.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/Foundations/discretization.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/Foundations/ocp.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/Foundations/scvx.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/Foundations/time_dilation.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UnderTheHood/lowering_architecture.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UnderTheHood/vectorization_and_vmapping.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/00_introduction.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/01_hello_world_brachistochrone.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/02_drone_racing_constraints.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/03_obstacle_avoidance_vmap.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/04_viewpoint_constraints.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/05_visualization.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/06_logic.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/UsersGuide/08_mpcc.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/assets/favicon.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/assets/images/ct-scvx_dark.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/assets/images/ct-scvx_light.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/assets/images/ctcs_dark.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/assets/images/ctcs_light.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/assets/images/problem_class_dark.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/assets/images/problem_class_light.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/assets/logo.svg +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/citation.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/examples.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/getting-started.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/index.md +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/docs/javascripts/mathjax.js +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/abstract/brachistochrone.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/abstract/impulsive.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/abstract/stl_integer_variable.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/abstract/stl_or.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/arm/3_dof_arm.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/arm/7_dof_arm.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/arm/7_dof_arm_vp.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/car/dubins_car.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/car/dubins_car_disjoint.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/car/dubins_car_obstacle_conditional.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/car/dubins_car_obstacle_stl.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/car/dubins_car_stl_or.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/car/dubins_car_waypoint_stl.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/cinema_vp.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/dr_double_integrator.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/dr_vp.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/dr_vp_nodal.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/dr_vp_polytope.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/drone_racing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/logo.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/logo_utils/acl_logo.svg +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/logo_utils/svg_path_utils.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/obstacle_avoidance.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/obstacle_avoidance_nodal.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/drone/obstacle_avoidance_vmap.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/mpc/double_integrator_discrete.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/mpc/double_integrator_drone_racing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/mpc/dubins_car_circle_analytical.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/mpc/dubins_car_circle_discrete.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/mpc/realtime_double_integrator_drone_racing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/plotting.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/3DoF_pdg_realtime.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/6DoF_pdg_realtime.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/base_problems/3DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/base_problems/6DoF_pdg_realtime_base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/base_problems/cinema_vp_realtime_base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/base_problems/drone_racing_realtime_base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/base_problems/dubins_car_realtime_base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/base_problems/obstacle_avoidance_realtime_base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/cinema_vp_realtime.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/drone_racing_realtime.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/dubins_car_realtime.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/realtime/obstacle_avoidance_realtime.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/rocket/3DoF_pdg.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/rocket/6DoF_pdg.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/spacecraft/halo_orbit.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/spacecraft/hohmann_transfer.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/examples/spacecraft/proxops_cw.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/figures/ctlos_cine.gif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/figures/ctlos_dr.gif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/figures/dtlos_cine.gif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/figures/dtlos_dr.gif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/figures/openscvx_logo.svg +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/figures/openscvx_logo_square.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/figures/oscvx_structure_full_dark.svg +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/figures/video_preview.png +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/1-background.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/1-background@1x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/1-background@2x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/1-background@3x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/1-background@4x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/2-mars.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/2-mars@1x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/2-mars@2x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/2-mars@3x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/2-mars@4x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/3-moon.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/3-moon@1x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/3-moon@2x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/3-moon@3x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/3-moon@4x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/4-sat1.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/4-sat1@1x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/4-sat1@2x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/4-sat1@3x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/4-sat1@4x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/5-space.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/5-space@1x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/5-space@2x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/5-space@3x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/5-space@4x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/6-earth.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/6-earth@1x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/6-earth@2x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/6-earth@3x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/images/layers/6-earth@4x.avif +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/javascripts/parallax.js +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/logo.svg +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/stylesheets/custom.css +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/assets/stylesheets/parallax.css +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/home.html +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/main.html +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/partials/parallax/hero.html +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/material/overrides/partials/parallax.html +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/mkdocs.yml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/__main__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/algorithms/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/algorithms/augmented_lagrangian.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/algorithms/base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/algorithms/constant_proximal_weight.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/algorithms/optimization_results.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/algorithms/penalized_trust_region.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/algorithms/ramp_proximal_weight.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/algorithms/weights.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/config.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/discretization/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/discretization/base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/discretization/discretize_linearize.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/discretization/linearize_discretize.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/discretization/linearize_discretize_sparse.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/discretization/sparse_utils/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/discretization/sparse_utils/bcoo_helpers.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/discretization/sparse_utils/sparse_jacobian.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/expert/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/expert/byof.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/expert/lowering.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/expert/validation.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/init/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/init/interpolation.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/init/inverse_kinematics.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/integrators/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/integrators/diffrax.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/integrators/runge_kutta.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/loader.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/lowered/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/lowered/cvxpy_constraints.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/lowered/cvxpy_variables.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/lowered/dynamics.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/lowered/jax_constraints.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/lowered/parameters.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/lowered/problem.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/lowered/unified.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/plotting.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/scp_iteration.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/viser/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/viser/orbits.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/viser/plotly_integration.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/viser/primitives.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/viser/scp.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/plotting/viser/server.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/problem.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/propagation/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/propagation/post_processing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/propagation/propagation.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/solvers/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/solvers/base.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/solvers/ptr_solver.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/augmentation.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/builder.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/constraint_set.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/arithmetic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/array.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/constraint.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/control.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/expr.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/lie/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/lie/adjoint.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/lie/se3.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/lie/so3.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/linalg.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/logic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/math.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/parameter.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/spatial.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/state.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/stl.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/stljax.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/time.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/variable.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/expr/vmap.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/hashing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lower.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/_lowerer.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/_registry.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/arithmetic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/array.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/constraint.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/control.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/expr.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/linalg.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/logic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/math.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/cvxpy/state.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/_lowerer.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/_registry.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/arithmetic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/array.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/constraint.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/control.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/expr.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/lie.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/linalg.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/logic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/math.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/spatial.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/state.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/stl.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/stljax.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/lowerers/jax/vmap.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/_registry.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/array.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/constraint.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/lie.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/linalg.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/logic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/math.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/parser.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/spatial.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/stl.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/stljax.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/parser/tokenizer.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/preprocessing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/problem.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/sparsity.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/symbolic/unified.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/utils/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/utils/cache.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/utils/caching.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/utils/printing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/utils/profiling.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx/utils/utils.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx.egg-info/dependency_links.txt +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx.egg-info/entry_points.txt +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx.egg-info/requires.txt +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/openscvx.egg-info/top_level.txt +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/pyproject.toml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/scripts/gen_example_pages.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/scripts/gen_ref_pages.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/setup.cfg +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/brachistochrone_analytical.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/expr/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/expr/test_gmsr.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/fixtures/brachistochrone.json +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/fixtures/brachistochrone.yaml +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/hohmann_analytical.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_arithmetic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_array.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_constraint.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_expr.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_lie.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_linalg.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_logic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_math.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_node_reference.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_parameters.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_scaling.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_spatial.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_stl.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_variable.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/expr/test_vmap.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/__init__.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_array.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_constraint.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_lie.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_linalg.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_load.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_logic.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_math.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_parser.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_spatial.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_stl.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_tokenizer.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/parser/test_vmap.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/test_augmentation.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/test_hashing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/test_lower_cvxpy.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/test_lower_jax.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/test_preprocessing.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/test_sparsity.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/symbolic/test_unified.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_autotuning.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_brachistochrone.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_cvxpygen_optional.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_discretization.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_expert.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_impulsive.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_init.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_integrators.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_loader.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_optimization_results.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_plotting.py +0 -0
- {openscvx-0.4.1.dev170 → openscvx-0.4.1.dev172}/tests/test_propagation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openscvx
|
|
3
|
-
Version: 0.4.1.
|
|
3
|
+
Version: 0.4.1.dev172
|
|
4
4
|
Summary: A general Python-based successive convexification implementation which uses a JAX backend.
|
|
5
5
|
Author-email: Chris Hayner and Griffin Norris <haynec@uw.edu>
|
|
6
6
|
License: Apache Software License
|
|
@@ -364,6 +364,98 @@ results = problem.post_process()
|
|
|
364
364
|
|
|
365
365
|
After solving, `results.trajectory["T_ee"]` gives you the dense end-effector transform along the propagated trajectory, ready to feed straight into a viser animation or a downstream controller.
|
|
366
366
|
|
|
367
|
+
## Extension: Self-Collision and Obstacle Avoidance
|
|
368
|
+
|
|
369
|
+
The same intermediate `joint_transforms` we snapshotted above give us everything we need to constrain the *arm itself*, not just its end-effector. The [7-DOF arm with collisions](../Examples/arm/7_dof_arm_collision.md) example extends the pick-and-place setup with two extra constraints:
|
|
370
|
+
|
|
371
|
+
- **Self-collision** between every pair of non-adjacent links.
|
|
372
|
+
- **Obstacle avoidance** between every link and a spherical obstacle placed on the table.
|
|
373
|
+
|
|
374
|
+
The idea is to approximate each link as a **capsule** (a sphere-swept line segment) between two consecutive keypoints, sample each capsule at a small grid of parameters $t \in [0, 1]$, and enforce a pairwise distance bound at every sample. `ox.Vmap` turns the inner loop into a single batched evaluation.
|
|
375
|
+
|
|
376
|
+
First, lift each keypoint from its home position into the world frame using the transforms we already built. We pad with a trailing `1` so the $4 \times 4$ homogeneous transform acts on it correctly:
|
|
377
|
+
|
|
378
|
+
```python
|
|
379
|
+
keypoint_home_pos = {
|
|
380
|
+
"base": np.array([0.0, 0.0, 0.0, 1.0]),
|
|
381
|
+
"shoulder": np.array([0.0, 0.0, d1, 1.0]),
|
|
382
|
+
"elbow": np.array([a2, 0.0, d1, 1.0]),
|
|
383
|
+
"wrist": np.array([a2 + a3, 0.0, d1, 1.0]),
|
|
384
|
+
"ee": np.array([a2 + a3 + a4, 0.0, d1, 1.0]),
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
def _keypoint_world(name):
|
|
388
|
+
p_hom = joint_transforms[name] @ ox.Constant(keypoint_home_pos[name])
|
|
389
|
+
return ox.Concat(p_hom[0], p_hom[1], p_hom[2])
|
|
390
|
+
|
|
391
|
+
kp = {name: _keypoint_world(name) for name in joint_names}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Then describe each link as `(start, end, radius)`:
|
|
395
|
+
|
|
396
|
+
```python
|
|
397
|
+
link_specs = [
|
|
398
|
+
("base", "shoulder", 0.06),
|
|
399
|
+
("shoulder", "elbow", 0.05),
|
|
400
|
+
("elbow", "wrist", 0.04),
|
|
401
|
+
("wrist", "ee", 0.035),
|
|
402
|
+
]
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Self-collision
|
|
406
|
+
|
|
407
|
+
For every pair of non-adjacent capsules, sample both segments on a $t \times t$ grid and enforce that the sum of radii stays under the sampled distance:
|
|
408
|
+
|
|
409
|
+
```python
|
|
410
|
+
n_samples = 4
|
|
411
|
+
ts = np.linspace(0.0, 1.0, n_samples)
|
|
412
|
+
tt = np.stack(np.meshgrid(ts, ts, indexing="ij"), axis=-1).reshape(-1, 2)
|
|
413
|
+
|
|
414
|
+
for i in range(len(link_specs)):
|
|
415
|
+
for j in range(i + 2, len(link_specs)): # skip adjacent (shared joint)
|
|
416
|
+
a_start, a_end, r_a = link_specs[i]
|
|
417
|
+
b_start, b_end, r_b = link_specs[j]
|
|
418
|
+
pa0, pa1 = kp[a_start], kp[a_end]
|
|
419
|
+
pb0, pb1 = kp[b_start], kp[b_end]
|
|
420
|
+
r_sum = r_a + r_b
|
|
421
|
+
|
|
422
|
+
dists = ox.Vmap(
|
|
423
|
+
lambda t, pa0=pa0, pa1=pa1, pb0=pb0, pb1=pb1: ox.linalg.Norm(
|
|
424
|
+
((1 - t[0]) * pa0 + t[0] * pa1)
|
|
425
|
+
- ((1 - t[1]) * pb0 + t[1] * pb1)
|
|
426
|
+
),
|
|
427
|
+
batch=tt,
|
|
428
|
+
)
|
|
429
|
+
constraints.append(ox.ctcs(r_sum <= dists))
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Skipping `j = i + 1` matters: adjacent capsules share a joint, so their minimum distance is identically zero and enforcing a strict capsule-capsule bound between them would be infeasible by construction.
|
|
433
|
+
|
|
434
|
+
### Obstacle avoidance
|
|
435
|
+
|
|
436
|
+
The same pattern handles a spherical obstacle — sample every link and keep it outside the inflated sphere:
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
obstacle_center = np.array([0.35, 0.0, 0.25])
|
|
440
|
+
obstacle_radius = 0.06
|
|
441
|
+
|
|
442
|
+
for a_start, a_end, r_link in link_specs:
|
|
443
|
+
pa0, pa1 = kp[a_start], kp[a_end]
|
|
444
|
+
r_clear = obstacle_radius + r_link
|
|
445
|
+
obs_dists = ox.Vmap(
|
|
446
|
+
lambda t, pa0=pa0, pa1=pa1: ox.linalg.Norm(
|
|
447
|
+
((1 - t) * pa0 + t * pa1) - ox.Constant(obstacle_center)
|
|
448
|
+
),
|
|
449
|
+
batch=ts,
|
|
450
|
+
)
|
|
451
|
+
constraints.append(ox.ctcs(r_clear <= obs_dists))
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Because each bound is wrapped in `ox.ctcs`, distances are enforced **continuously** along the trajectory — capsules cannot tunnel between nodes.
|
|
455
|
+
|
|
456
|
+
!!! warning "Numerical performance"
|
|
457
|
+
Solve times on this example are currently noticeably slower than we would like when self-collision checking is included; expect a meaningful jump compared to the raw pick-and-place. We are actively working on it.
|
|
458
|
+
|
|
367
459
|
## Key Takeaways
|
|
368
460
|
|
|
369
461
|
1. **Start simple with the minimal representation.** Joint angles + velocities give a pure ODE that drops cleanly into OpenSCvx's modeling stack — the easiest place to begin. Maximal coordinates are also a strong (and in some respects superior) choice for trajopt and will get their own tutorial in the future. The consequence of working in joint space is that task-space quantities are no longer states — they are symbolic functions of the state.
|
|
@@ -377,4 +469,5 @@ After solving, `results.trajectory["T_ee"]` gives you the dense end-effector tra
|
|
|
377
469
|
- [API Reference: Lie algebra](../Reference/symbolic/expr/lie/index.md)
|
|
378
470
|
- [Three-link arm Example](../Examples/arm/3_dof_arm.md)
|
|
379
471
|
- [Seven-link arm Example](../Examples/arm/7_dof_arm.md)
|
|
472
|
+
- [Seven-link arm with self-collision Example](../Examples/arm/7_dof_arm_collision.md)
|
|
380
473
|
- [Seven-link arm with viewcone Example](../Examples/arm/7_dof_arm_vp.md)
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Cinematic offline render of the 7-DOF arm pick-and-place example.
|
|
2
|
+
|
|
3
|
+
The trajectory optimization problem itself lives in
|
|
4
|
+
``examples/arm/7_dof_arm.py``; this file imports that ``problem`` and the
|
|
5
|
+
robot parameters, solves it, builds a viser scene with arm links / joint
|
|
6
|
+
frames / EE trail, and drives it frame-by-frame while piping raw RGB into
|
|
7
|
+
ffmpeg to produce an mp4.
|
|
8
|
+
|
|
9
|
+
Run it with::
|
|
10
|
+
|
|
11
|
+
python examples/animations/7_dof_arm.py
|
|
12
|
+
|
|
13
|
+
The script prints a viser URL and waits. Open the URL in a browser — as soon
|
|
14
|
+
as the client connects, the render begins. Requires ``ffmpeg`` on ``PATH``;
|
|
15
|
+
``openscvx`` does not depend on it.
|
|
16
|
+
|
|
17
|
+
Only one camera mode is provided — ``"overview"`` — a static elevated camera
|
|
18
|
+
that frames the full pick-and-place workspace.
|
|
19
|
+
|
|
20
|
+
Tweak ``OUTPUT_PATH`` / ``WIDTH`` / ``HEIGHT`` / ``FPS`` below for different
|
|
21
|
+
output variants.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import importlib
|
|
25
|
+
import os
|
|
26
|
+
import sys
|
|
27
|
+
|
|
28
|
+
import numpy as np
|
|
29
|
+
|
|
30
|
+
# Add the project root so `examples.*` imports resolve.
|
|
31
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
32
|
+
grandparent_dir = os.path.dirname(os.path.dirname(current_dir))
|
|
33
|
+
sys.path.append(grandparent_dir)
|
|
34
|
+
|
|
35
|
+
from examples.animations._camera import overview_pose
|
|
36
|
+
from examples.animations._render import render_animation_to_video
|
|
37
|
+
from examples.plotting_viser import AnimatedServerHandle
|
|
38
|
+
from openscvx.plotting.viser import (
|
|
39
|
+
add_animated_trail,
|
|
40
|
+
add_ellipsoid_obstacles,
|
|
41
|
+
add_ghost_trajectory,
|
|
42
|
+
add_position_marker,
|
|
43
|
+
add_target_markers,
|
|
44
|
+
compute_velocity_colors,
|
|
45
|
+
create_server,
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Import the arm example by path (filename starts with a digit).
|
|
49
|
+
_arm_spec = importlib.util.spec_from_file_location(
|
|
50
|
+
"arm_7dof", os.path.join(grandparent_dir, "examples", "arm", "7_dof_arm_collision.py")
|
|
51
|
+
)
|
|
52
|
+
_arm_mod = importlib.util.module_from_spec(_arm_spec)
|
|
53
|
+
_arm_spec.loader.exec_module(_arm_mod)
|
|
54
|
+
|
|
55
|
+
problem = _arm_mod.problem
|
|
56
|
+
d1 = _arm_mod.d1
|
|
57
|
+
a2 = _arm_mod.a2
|
|
58
|
+
a3 = _arm_mod.a3
|
|
59
|
+
a4 = _arm_mod.a4
|
|
60
|
+
joint_names = _arm_mod.joint_names
|
|
61
|
+
waypoint_names = _arm_mod.waypoint_names
|
|
62
|
+
waypoint_positions = _arm_mod.waypoint_positions
|
|
63
|
+
obstacle_center = _arm_mod.obstacle_center
|
|
64
|
+
obstacle_radius = _arm_mod.obstacle_radius
|
|
65
|
+
|
|
66
|
+
# Keypoint home positions (derived from link lengths — defined in __main__ of
|
|
67
|
+
# the arm example, so we replicate them here).
|
|
68
|
+
keypoint_home_positions = {
|
|
69
|
+
"base": np.array([0.0, 0.0, 0.0]),
|
|
70
|
+
"shoulder": np.array([0.0, 0.0, d1]),
|
|
71
|
+
"elbow": np.array([a2, 0.0, d1]),
|
|
72
|
+
"wrist": np.array([a2 + a3, 0.0, d1]),
|
|
73
|
+
"ee": np.array([a2 + a3 + a4, 0.0, d1]),
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# --- Render settings ---------------------------------------------------------
|
|
77
|
+
OUTPUT_PATH = os.path.join(current_dir, "mp4", "7_dof_arm_overview.mp4")
|
|
78
|
+
WIDTH = 1080
|
|
79
|
+
HEIGHT = 1080
|
|
80
|
+
FPS = 60
|
|
81
|
+
CRF = 16
|
|
82
|
+
|
|
83
|
+
# Oversampling for smooth trails.
|
|
84
|
+
STRIDE = 4
|
|
85
|
+
PROPAGATION_HZ = FPS * STRIDE
|
|
86
|
+
|
|
87
|
+
# --- Camera settings ---------------------------------------------------------
|
|
88
|
+
OVERVIEW_AZIMUTH = np.radians(60.0)
|
|
89
|
+
OVERVIEW_ELEVATION = np.radians(15.0)
|
|
90
|
+
OVERVIEW_RADIUS_MARGIN = 1.0
|
|
91
|
+
OVERVIEW_FOV_DEG = 60.0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
import jaxlie
|
|
96
|
+
|
|
97
|
+
problem.settings.prp.dt = 1.0 / PROPAGATION_HZ
|
|
98
|
+
problem.initialize()
|
|
99
|
+
problem.solve()
|
|
100
|
+
results = problem.post_process()
|
|
101
|
+
|
|
102
|
+
ee_pos = np.asarray(results.trajectory["ee_position"], dtype=np.float64)
|
|
103
|
+
n_frames = len(ee_pos)
|
|
104
|
+
|
|
105
|
+
# -- Extract joint keypoint positions from propagated transforms -----------
|
|
106
|
+
keypoints = np.zeros((n_frames, 5, 3))
|
|
107
|
+
joint_quats = np.zeros((n_frames, 5, 4))
|
|
108
|
+
for k, name in enumerate(joint_names):
|
|
109
|
+
T_k = np.asarray(results.trajectory[f"T_{name}"]) # (T, 4, 4)
|
|
110
|
+
p_home = np.append(keypoint_home_positions[name], 1.0)
|
|
111
|
+
keypoints[:, k] = (T_k @ p_home)[:, :3]
|
|
112
|
+
joint_quats[:, k] = np.array(
|
|
113
|
+
[jaxlie.SO3.from_matrix(T_k[t, :3, :3]).wxyz for t in range(n_frames)]
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# -- Build viser scene (mirrors examples/arm/7_dof_arm.py) -----------------
|
|
117
|
+
server = create_server(ee_pos, show_grid=False)
|
|
118
|
+
server.scene.add_grid("/grid", width=1.5, height=1.5, cell_size=0.25)
|
|
119
|
+
server.scene.add_frame("/origin", axes_length=0.1, axes_radius=0.003)
|
|
120
|
+
|
|
121
|
+
# Waypoint markers
|
|
122
|
+
marker_colors = {
|
|
123
|
+
"home": (100, 150, 255),
|
|
124
|
+
"pre_grasp": (255, 180, 50),
|
|
125
|
+
"grasp": (255, 50, 50),
|
|
126
|
+
"pre_place": (255, 180, 50),
|
|
127
|
+
"place": (255, 50, 50),
|
|
128
|
+
}
|
|
129
|
+
add_target_markers(
|
|
130
|
+
server,
|
|
131
|
+
waypoint_positions,
|
|
132
|
+
radius=0.015,
|
|
133
|
+
colors=[marker_colors[name] for name in waypoint_names],
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
add_ellipsoid_obstacles(
|
|
137
|
+
server,
|
|
138
|
+
centers=[obstacle_center],
|
|
139
|
+
radii=[np.full(3, 1.0 / obstacle_radius)],
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Ghost EE trajectory + animated trail
|
|
143
|
+
ee_colors = compute_velocity_colors(np.asarray(results.trajectory.get("velocity")))
|
|
144
|
+
add_ghost_trajectory(server, ee_pos, ee_colors, point_size=0.005)
|
|
145
|
+
_, update_trail = add_animated_trail(server, ee_pos, ee_colors, point_size=0.008)
|
|
146
|
+
|
|
147
|
+
# Animated EE position marker
|
|
148
|
+
_, update_marker = add_position_marker(server, ee_pos, radius=0.015)
|
|
149
|
+
|
|
150
|
+
# Animated arm links (line segments between consecutive keypoints)
|
|
151
|
+
link_rgb = np.array(
|
|
152
|
+
[
|
|
153
|
+
[180, 180, 180], # base -> shoulder
|
|
154
|
+
[100, 180, 255], # shoulder -> elbow
|
|
155
|
+
[100, 255, 150], # elbow -> wrist
|
|
156
|
+
[255, 200, 100], # wrist -> ee
|
|
157
|
+
],
|
|
158
|
+
dtype=np.uint8,
|
|
159
|
+
)
|
|
160
|
+
link_colors = np.stack([link_rgb, link_rgb], axis=1) # (4, 2, 3)
|
|
161
|
+
|
|
162
|
+
init_points = np.stack(
|
|
163
|
+
[np.stack([keypoints[0, k], keypoints[0, k + 1]]) for k in range(4)]
|
|
164
|
+
).astype(np.float32)
|
|
165
|
+
|
|
166
|
+
arm_handle = server.scene.add_line_segments(
|
|
167
|
+
"/arm_links",
|
|
168
|
+
points=init_points,
|
|
169
|
+
colors=link_colors,
|
|
170
|
+
line_width=5.0,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Joint coordinate frames
|
|
174
|
+
joint_frame_handles = []
|
|
175
|
+
for k in range(5):
|
|
176
|
+
h = server.scene.add_frame(
|
|
177
|
+
f"/joint_{joint_names[k]}",
|
|
178
|
+
wxyz=joint_quats[0, k].astype(np.float32),
|
|
179
|
+
position=keypoints[0, k].astype(np.float32),
|
|
180
|
+
axes_length=0.06,
|
|
181
|
+
axes_radius=0.002,
|
|
182
|
+
)
|
|
183
|
+
joint_frame_handles.append(h)
|
|
184
|
+
|
|
185
|
+
def update_arm(frame_idx: int) -> None:
|
|
186
|
+
pts = np.stack(
|
|
187
|
+
[np.stack([keypoints[frame_idx, k], keypoints[frame_idx, k + 1]]) for k in range(4)]
|
|
188
|
+
).astype(np.float32)
|
|
189
|
+
arm_handle.points = pts
|
|
190
|
+
for k, h in enumerate(joint_frame_handles):
|
|
191
|
+
h.position = keypoints[frame_idx, k].astype(np.float32)
|
|
192
|
+
h.wxyz = joint_quats[frame_idx, k].astype(np.float32)
|
|
193
|
+
|
|
194
|
+
# -- Manual-step handle for the renderer -----------------------------------
|
|
195
|
+
traj_time = np.asarray(results.trajectory["time"], dtype=np.float64).flatten()
|
|
196
|
+
handle = AnimatedServerHandle(
|
|
197
|
+
server=server,
|
|
198
|
+
traj_time=traj_time,
|
|
199
|
+
update_callbacks=[update_trail, update_marker, update_arm],
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# -- Camera: overview framing the full workspace ---------------------------
|
|
203
|
+
# Frame on waypoint positions + EE path so the full motion is visible.
|
|
204
|
+
all_points = np.vstack([ee_pos, np.array(waypoint_positions)])
|
|
205
|
+
static_pose = overview_pose(
|
|
206
|
+
all_points,
|
|
207
|
+
azimuth=OVERVIEW_AZIMUTH,
|
|
208
|
+
elevation=OVERVIEW_ELEVATION,
|
|
209
|
+
radius_margin=OVERVIEW_RADIUS_MARGIN,
|
|
210
|
+
fov_deg=OVERVIEW_FOV_DEG,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
def camera_pose_fn(frame_idx: int):
|
|
214
|
+
return static_pose
|
|
215
|
+
|
|
216
|
+
render_animation_to_video(
|
|
217
|
+
handle,
|
|
218
|
+
OUTPUT_PATH,
|
|
219
|
+
camera_pose_fn,
|
|
220
|
+
width=WIDTH,
|
|
221
|
+
height=HEIGHT,
|
|
222
|
+
fps=FPS,
|
|
223
|
+
crf=CRF,
|
|
224
|
+
stride=STRIDE,
|
|
225
|
+
)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"""Reusable camera pose helpers for viser animation rendering.
|
|
2
|
+
|
|
3
|
+
All functions return ``(cam_position, cam_wxyz, look_at)`` tuples suitable for
|
|
4
|
+
passing to ``render_animation_to_video``'s ``camera_pose_fn`` argument. They
|
|
5
|
+
depend only on numpy and ``viser.transforms`` — no openscvx imports.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
import viser.transforms as vtf
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def look_at_wxyz(pos: np.ndarray, target: np.ndarray, up: np.ndarray) -> np.ndarray:
|
|
15
|
+
"""Quaternion (w,x,y,z) for a camera at ``pos`` looking at ``target``.
|
|
16
|
+
|
|
17
|
+
Uses the OpenCV camera convention that viser expects: +X right, +Y down,
|
|
18
|
+
+Z forward. See ``examples/animations/camera_control_notes.md``.
|
|
19
|
+
"""
|
|
20
|
+
forward = target - pos
|
|
21
|
+
forward /= np.linalg.norm(forward)
|
|
22
|
+
right = np.cross(forward, up)
|
|
23
|
+
right_norm = np.linalg.norm(right)
|
|
24
|
+
if right_norm < 1e-6:
|
|
25
|
+
# Gimbal lock: forward is (nearly) parallel to up. Pick an arbitrary
|
|
26
|
+
# world axis that isn't, so the camera stays defined. The chosen axis
|
|
27
|
+
# determines the "roll" of the camera at the singularity — not great
|
|
28
|
+
# cinematically, but prevents a NaN crash.
|
|
29
|
+
fallback = np.array([1.0, 0.0, 0.0]) if abs(forward[0]) < 0.9 else np.array([0.0, 1.0, 0.0])
|
|
30
|
+
right = np.cross(forward, fallback)
|
|
31
|
+
right_norm = np.linalg.norm(right)
|
|
32
|
+
right /= right_norm
|
|
33
|
+
cam_down = np.cross(forward, right) # = -world_up projected perp to forward
|
|
34
|
+
R_world_cam = np.stack([right, cam_down, forward], axis=1)
|
|
35
|
+
return vtf.SO3.from_matrix(R_world_cam).wxyz
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def chase_pose(
|
|
39
|
+
subject: np.ndarray,
|
|
40
|
+
focus: np.ndarray,
|
|
41
|
+
*,
|
|
42
|
+
chase_distance: float = 15.0,
|
|
43
|
+
vertical_offset: float = 2.0,
|
|
44
|
+
up=(0.0, 0.0, 1.0),
|
|
45
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
46
|
+
"""Return ``(cam_pos, cam_wxyz, look_at)`` for a chase camera behind ``subject``.
|
|
47
|
+
|
|
48
|
+
The camera sits on the ray from ``focus`` through ``subject``, extended
|
|
49
|
+
``chase_distance`` units past the subject, then lifted along world up by
|
|
50
|
+
``vertical_offset``. It always looks at ``focus``.
|
|
51
|
+
"""
|
|
52
|
+
subject = np.asarray(subject, dtype=np.float64)
|
|
53
|
+
focus = np.asarray(focus, dtype=np.float64)
|
|
54
|
+
up = np.asarray(up, dtype=np.float64)
|
|
55
|
+
|
|
56
|
+
ray = subject - focus
|
|
57
|
+
ray_norm = np.linalg.norm(ray)
|
|
58
|
+
if ray_norm < 1e-6:
|
|
59
|
+
cam_pos = subject + vertical_offset * up
|
|
60
|
+
else:
|
|
61
|
+
cam_pos = subject + chase_distance * (ray / ray_norm) + vertical_offset * up
|
|
62
|
+
|
|
63
|
+
wxyz = look_at_wxyz(cam_pos, focus, up)
|
|
64
|
+
return cam_pos, wxyz, focus
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def onboard_pose(
|
|
68
|
+
position: np.ndarray,
|
|
69
|
+
attitude_wxyz: np.ndarray,
|
|
70
|
+
R_sb: np.ndarray,
|
|
71
|
+
*,
|
|
72
|
+
forward_offset: float = 0.0,
|
|
73
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
74
|
+
"""Return ``(cam_pos, cam_wxyz, look_at)`` for a sensor-mounted FPV camera.
|
|
75
|
+
|
|
76
|
+
Places the camera at ``position`` (shifted slightly forward along the sensor
|
|
77
|
+
boresight by ``forward_offset``) with orientation matching the sensor frame —
|
|
78
|
+
i.e. looking along the sensor boresight (+Z in sensor frame, mapped through
|
|
79
|
+
``R_sb`` and the body attitude to world coordinates).
|
|
80
|
+
"""
|
|
81
|
+
# R_body_to_world from the attitude quaternion (w, x, y, z)
|
|
82
|
+
w, x, y, z = attitude_wxyz
|
|
83
|
+
R_bw = np.array(
|
|
84
|
+
[
|
|
85
|
+
[1 - 2 * (y * y + z * z), 2 * (x * y - z * w), 2 * (x * z + y * w)],
|
|
86
|
+
[2 * (x * y + z * w), 1 - 2 * (x * x + z * z), 2 * (y * z - x * w)],
|
|
87
|
+
[2 * (x * z - y * w), 2 * (y * z + x * w), 1 - 2 * (x * x + y * y)],
|
|
88
|
+
],
|
|
89
|
+
dtype=np.float64,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
# Sensor-to-world: columns are the sensor axes in world coords.
|
|
93
|
+
# R_sb is body-to-sensor, so R_sb.T is sensor-to-body.
|
|
94
|
+
R_sensor_to_world = R_bw @ R_sb.T
|
|
95
|
+
|
|
96
|
+
# Viser uses OpenCV convention (+X right, +Y DOWN, +Z forward).
|
|
97
|
+
# The sensor frame has +Y UP, so we rotate 180deg around the boresight (Z)
|
|
98
|
+
# to flip both X and Y, converting to the convention viser expects.
|
|
99
|
+
R_opencv_from_sensor = np.diag([-1.0, -1.0, 1.0])
|
|
100
|
+
R_cam_to_world = R_sensor_to_world @ R_opencv_from_sensor
|
|
101
|
+
|
|
102
|
+
wxyz = vtf.SO3.from_matrix(R_cam_to_world).wxyz
|
|
103
|
+
# Boresight is sensor +Z expressed in world frame (unchanged by the flip).
|
|
104
|
+
boresight_world = R_sensor_to_world[:, 2]
|
|
105
|
+
cam_pos = position + forward_offset * boresight_world
|
|
106
|
+
look_at = cam_pos + 10.0 * boresight_world
|
|
107
|
+
return cam_pos, wxyz, look_at
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def overview_pose(
|
|
111
|
+
positions: np.ndarray,
|
|
112
|
+
*,
|
|
113
|
+
azimuth: float = np.radians(135.0),
|
|
114
|
+
elevation: float = np.radians(25.0),
|
|
115
|
+
radius_margin: float = 0.75,
|
|
116
|
+
fov_deg: float = 60.0,
|
|
117
|
+
up=(0.0, 0.0, 1.0),
|
|
118
|
+
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
119
|
+
"""Return a static ``(cam_pos, cam_wxyz, look_at)`` that frames all ``positions``.
|
|
120
|
+
|
|
121
|
+
The camera is placed on a sphere around the centroid of ``positions``,
|
|
122
|
+
parameterized by ``azimuth`` (angle in XY from +X, CCW) and ``elevation``
|
|
123
|
+
(angle above the horizon). The radius is auto-computed so the full extent
|
|
124
|
+
fits within ``fov_deg``, then scaled by ``radius_margin``.
|
|
125
|
+
"""
|
|
126
|
+
up = np.asarray(up, dtype=np.float64)
|
|
127
|
+
center = positions.mean(axis=0)
|
|
128
|
+
max_extent = np.max(np.linalg.norm(positions - center, axis=1))
|
|
129
|
+
half_fov_rad = np.radians(fov_deg / 2.0)
|
|
130
|
+
radius = max_extent / np.sin(half_fov_rad) * radius_margin
|
|
131
|
+
|
|
132
|
+
cos_el = np.cos(elevation)
|
|
133
|
+
cam_pos = center + radius * np.array(
|
|
134
|
+
[
|
|
135
|
+
cos_el * np.cos(azimuth),
|
|
136
|
+
cos_el * np.sin(azimuth),
|
|
137
|
+
np.sin(elevation),
|
|
138
|
+
]
|
|
139
|
+
)
|
|
140
|
+
look_at = center.copy()
|
|
141
|
+
wxyz = look_at_wxyz(cam_pos, look_at, up)
|
|
142
|
+
return cam_pos, wxyz, look_at
|