Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
2943d90
Bug fixes for holonomic contraints with robotics
Sep 25, 2025
0e5b565
Merge branch 'HolonomicForRobotics'
Feb 11, 2026
71770fb
Fix: biais vector
EveCharbie Feb 16, 2026
17fce15
Update holonomic constraints
Ipuch Feb 5, 2026
2232466
rigid contact biais
Ipuch Feb 5, 2026
77c5d96
documentation ++
Ipuch Feb 5, 2026
cc01d66
..
Feb 16, 2026
4c489c7
Unstash examples
Feb 16, 2026
8603fab
Unstash examples
Feb 16, 2026
592ee98
Unstash examples
Feb 16, 2026
20f2456
Unstash examples
Feb 16, 2026
7b85eb9
Fix display of lagrange multipliers
Feb 20, 2026
51eb234
Track algebraic state
Mar 3, 2026
e7734bc
Mayer Track algebraic state
Mar 3, 2026
8c65762
WIP on holonomic alignment constraint
Apr 3, 2026
4748864
Cleaned constraints file
Apr 3, 2026
c43751d
Added example for generalized version of constraint
Apr 13, 2026
a2f6e51
Merge remote-tracking branch 'pyomeca/master' into AlignmentContraint…
Apr 13, 2026
11484cb
Added tests, RTR
Apr 13, 2026
e6ed671
Merge branch 'master' into AlignmentContraintExamples_andBugFixes
Apr 13, 2026
33f98e4
Fixing after merging branch from ipuch
Apr 13, 2026
22cd82e
.
Aug 4, 2025
03501aa
reducing memorie consumption and speed up solution building for large oc
Aug 19, 2025
2e516b8
quick fix
Nov 7, 2025
d9de29e
Require NumPy 2.4 in env and CI
mickaelbegon May 6, 2026
b853430
Fix SelectionMapping for NumPy 2
mickaelbegon May 6, 2026
c769ce0
Target biorbd 1.12 in default environment
mickaelbegon May 6, 2026
5798954
Fixed an unstable test
pariterre Jun 2, 2026
a1bcbf8
Typo
pariterre Jun 2, 2026
a8de7a3
Enable macOS online plotting via multiprocess server
mickaelbegon Apr 9, 2026
a31418d
Harden macOS plotting example fallbacks
mickaelbegon Apr 9, 2026
dbaef69
Fixed test
pariterre Jun 2, 2026
64fb533
test_fatigable_effort_torque_split only on Darwin
pariterre Jun 2, 2026
e4c56b1
Small refactor
pariterre Jun 3, 2026
6177ce8
Fix lambda function for OnlineCallbackMultiprocess
pariterre Jun 3, 2026
1a6c05c
Add optional Pinocchio model backend
mickaelbegon May 6, 2026
0c57033
Document Pinocchio equivalents and derivative hooks
mickaelbegon May 6, 2026
1b6cf20
Better install of pinocchio
pariterre Jun 2, 2026
31c6086
Made SERVER_MULTIPROCESS default on linux
pariterre Jun 2, 2026
f5d4bc2
First working example of a pinocchio model
pariterre Jun 2, 2026
024a3aa
Added actual tests for pinocchio
pariterre Jun 2, 2026
94faa7e
Reinstated parameters test as it works now
pariterre Jun 2, 2026
3001da7
Blacked (and updated doc for black)
pariterre Jun 2, 2026
23c57da
Augmented tests for biorbd_model and pinocchio_model
pariterre Jun 3, 2026
ad34885
Better vscode launch file
pariterre Jun 3, 2026
c73e58f
Removed a useless test
pariterre Jun 3, 2026
469e47c
Removed pinocchio sensitive test values
pariterre Jun 3, 2026
441c659
Balancing tests to save time on CI
pariterre Jun 3, 2026
6175aef
Balancing yet again
pariterre Jun 3, 2026
d74c096
Final balancing
pariterre Jun 4, 2026
b9e6c34
WIP on PR comments
Jul 22, 2026
c94a5e4
Working through comments on the PR
Jul 22, 2026
45c75a6
Updated tests
Jul 22, 2026
60e89a5
Minor clean for test
Jul 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/run_tests_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ jobs:
conda list

- name: Install extra dependencies
run: |
conda install pip pytest-cov black pytest pytest-cov codecov packaging pytest-mpl -cconda-forge
run: |
conda install "numpy>=2.4,<3" pip pytest-cov black pytest pytest-cov codecov packaging pytest-mpl -cconda-forge
sudo apt install -y librhash-dev

- name: Install ACADOS on Linux
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run_tests_osx_win.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
conda list

- name: Install extra dependencies
run: conda install pip pytest-cov black pytest pytest-cov codecov packaging -cconda-forge
run: conda install "numpy>=2.4,<3" pip pytest-cov black pytest pytest-cov codecov packaging -cconda-forge

- name: Install ACADOS on Mac
run: |
Expand Down
34 changes: 11 additions & 23 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,39 @@
"version": "0.2.0",
"configurations": [
{
"name": "Run examples GUI",
"name": "Getting Started",
"type": "debugpy",
"request": "launch",
"module": "bioptim.examples",
"program": "${workspaceFolder}/bioptim/examples/getting_started/basic_ocp.py",
"console": "integratedTerminal",
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"cwd": "${fileDirname}"
"cwd": "${workspaceFolder}/bioptim/examples/getting_started/"
},
{
"name": "Python : fichier actif",
"name": "Run examples GUI",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": false,
"module": "bioptim.examples",
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"cwd": "${fileDirname}"
},
{
"name": "Pendulum",
"name": "Python : fichier actif",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/bioptim/examples/getting_started/pendulum.py",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": true,
"justMyCode": false,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"cwd": "${workspaceFolder}/bioptim/examples/getting_started/"
"cwd": "${fileDirname}"
},
{
"name": "Parameter",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/bioptim/examples/muscle_driven_ocp/custom_parameters.py",
"console": "integratedTerminal",
"justMyCode": true,
"env": {
"PYTHONPATH": "${workspaceFolder}"
},
"cwd": "${workspaceFolder}/bioptim/examples/muscle_driven_ocp/"
}
]
}
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -788,14 +788,15 @@ One can refer to their respective solver's documentation to know which options e
The `show_online_optim` parameter can be set to `True` so the graphs nicely update during the optimization with the default values.
One can also directly declare `online_optim` as an `OnlineOptim` parameter to customize the behavior of the plotter.
Note that `show_online_optim` and `online_optim` are mutually exclusive.
Please also note that `OnlineOptim.MULTIPROCESS` is not available on Windows and only none of them are available on Macos.
To see how to run the server on Windows, please refer to the `getting_started/pendulum.py` example.
Please also note that `OnlineOptim.MULTIPROCESS` is not available on Windows or Macos.
On Macos, the default backend is `OnlineOptim.MULTIPROCESS_SERVER`, while `OnlineOptim.SERVER` remains available if one wants to start `resources/plotting_server.py` manually.
To see how to run the server explicitly, please refer to the `resources/plotting_server.py` example.
It is expected to slow down the optimization a bit.
`show_options` can be also passed as a dict to the plotter to customize the plotter's behavior.
If `online_optim` is set to `SERVER`, then a server must be started manually by instantiating an `PlottingServer` class (see `ressources/plotting_server.py`).
The following keys are additional options when using `OnlineOptim.SERVER` and `OnlineOptim.MULTIPROCESS_SERVER`:
- `host`: the host to use (default is `localhost`)
- `port`: the port to use (default is `5030`)
- `port`: the port to use (default is `5030` for `OnlineOptim.SERVER` and a random available port for `OnlineOptim.MULTIPROCESS_SERVER`)

If you want to see IPOPT's iterations over the course of the resolution of your opc, it is possible using the following:
```python
Expand Down Expand Up @@ -1720,7 +1721,7 @@ The type of online plotter to use.

The accepted values are:
NONE: No online plotter.
DEFAULT: Use the default online plotter depending on the OS (MULTIPROCESS on Linux, MULTIPROCESS_SERVER on Windows and NONE on MacOS).
DEFAULT: Use the default online plotter depending on the OS (MULTIPROCESS on Linux, MULTIPROCESS_SERVER on Windows and macOS).
MULTIPROCESS: The online plotter is in a separate process.
SERVER: The online plotter is in a separate server.
MULTIPROCESS_SERVER: The online plotter using the server automatically setup on a separate process.
Expand Down Expand Up @@ -2006,6 +2007,9 @@ available in the `biorbd` documentation.
### The [example_optimal_time.py](./bioptim/examples/getting_started/example_optimal_time.py) file
Examples of time optimization can be found in 'examples/optimal_time_ocp/'.

### The [example_pinocchio.py](./bioptim/examples/getting_started/example_pinocchio.py) file
This example is the exact same as the pendulum example, but with a model defined using the `Pinocchio` backend (instead of the `biorbd` backend). It is designed to show how to use a model defined in Pinocchio instead of biorbd.

### The [example_simulation.py](./bioptim/examples/getting_started/example_simulation.py) file
The first part of this example is a single shooting simulation from initial guesses.
It is not an optimal control program. It is merely the simulation of values that is applying the dynamics.
Expand Down
1 change: 1 addition & 0 deletions bioptim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
JointAccelerationBiorbdModel,
MultiTorqueBiorbdModel,
)
from .models.pinocchio import PinocchioModel, TorquePinocchioModel
from .models.protocols.biomodel import BioModel
from .models.protocols.holonomic_constraints import HolonomicConstraintsFcn, HolonomicConstraintsList
from .models.protocols.stochastic_biomodel import StochasticBioModel
Expand Down
75 changes: 57 additions & 18 deletions bioptim/dynamics/configure_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
from typing import Callable, Any

import numpy as np
from casadi import DM, vertcat, Function
from casadi import DM, vertcat, Function, horzcat

from .configure_new_variable import NewVariableConfiguration
from .fatigue.fatigue_dynamics import FatigueList
from ..misc.enums import PlotType, ContactType
from ..misc.enums import PlotType, ContactType, ControlType
from ..misc.fcn_enum import FcnEnum
from ..misc.mapping import BiMapping, Mapping
from ..models.protocols.stochastic_biomodel import StochasticBioModel
Expand Down Expand Up @@ -1204,20 +1204,31 @@ def configure_qv(ocp, nlp, **extra_params) -> None:

time_span_sym = vertcat(nlp.time_cx, nlp.dt)

nlp.q_v_function = Function(
sym_qv = (
nlp.controls.scaled.cx
if nlp.control_type == ControlType.CONSTANT
else nlp.cx.sym("new_control", nlp.controls.scaled.cx.shape[0], 2)
)
qv_init_w_algebraic = (
nlp.algebraic_states["q_v"].cx
if "q_v" in nlp.algebraic_states.keys()
else DM.zeros(nlp.model.nb_dependent_joints, 1)
)

q_v_plot_function = Function(
"qv_function",
[
time_span_sym,
nlp.states.cx,
nlp.controls.cx,
nlp.parameters.cx,
nlp.algebraic_states.cx,
nlp.states.scaled.cx,
sym_qv,
nlp.parameters.scaled.cx,
nlp.algebraic_states.scaled.cx,
nlp.numerical_timeseries.cx,
],
[
nlp.model.compute_q_v()(
nlp.states["q_u"].cx,
DM.zeros(nlp.model.nb_dependent_joints, 1),
qv_init_w_algebraic,
)
],
["t_span", "x", "u", "p", "a", "d"],
Expand All @@ -1239,7 +1250,7 @@ def configure_qv(ocp, nlp, **extra_params) -> None:
)

nlp.plot["q_v"] = CustomPlot(
lambda t0, phases_dt, node_idx, x, u, p, a, d: nlp.q_v_function(
lambda t0, phases_dt, node_idx, x, u, p, a, d: q_v_plot_function(
np.concatenate([t0, t0 + phases_dt[nlp.phase_idx]]), x, u, p, a, d
),
plot_type=PlotType.INTEGRATED,
Expand All @@ -1261,12 +1272,24 @@ def configure_qdotv(ocp, nlp, **extra_params) -> None:
"""

time_span_sym = vertcat(nlp.time_cx, nlp.dt)
nlp.q_v_function = Function(

sym_qv = (
nlp.controls.scaled.cx
if nlp.control_type == ControlType.CONSTANT
else nlp.cx.sym("new_control", nlp.controls.scaled.cx.shape[0], 2)
)
qv_init_w_algebraic = (
nlp.algebraic_states["q_v"].cx
if "q_v" in nlp.algebraic_states.keys()
else DM.zeros(nlp.model.nb_dependent_joints, 1)
)

qdot_v_plot_function = Function(
"qdot_v_function",
[
time_span_sym,
nlp.states.scaled.cx,
nlp.controls.scaled.cx,
sym_qv,
nlp.parameters.scaled.cx,
nlp.algebraic_states.scaled.cx,
nlp.numerical_timeseries.cx,
Expand All @@ -1275,7 +1298,7 @@ def configure_qdotv(ocp, nlp, **extra_params) -> None:
nlp.model._compute_qdot_v()(
nlp.states.scaled["q_u"].cx,
nlp.states.scaled["qdot_u"].cx,
DM.zeros(nlp.model.nb_dependent_joints, 1),
qv_init_w_algebraic,
)
],
["t_span", "x", "u", "p", "a", "d"],
Expand All @@ -1297,7 +1320,7 @@ def configure_qdotv(ocp, nlp, **extra_params) -> None:
)

nlp.plot["qdot_v"] = CustomPlot(
lambda t0, phases_dt, node_idx, x, u, p, a, d: nlp.q_v_function(
lambda t0, phases_dt, node_idx, x, u, p, a, d: qdot_v_plot_function(
np.concatenate([t0, t0 + phases_dt[nlp.phase_idx]]), x, u, p, a, d
),
plot_type=PlotType.INTEGRATED,
Expand All @@ -1319,12 +1342,25 @@ def configure_lagrange_multipliers_function(ocp, nlp: NpArrayDictOptional, **ext
"""

time_span_sym = vertcat(nlp.time_cx, nlp.dt)
nlp.lagrange_multipliers_function = Function(

sym_qv = (
nlp.controls.scaled.cx
if nlp.control_type == ControlType.CONSTANT
else nlp.cx.sym("new_control", nlp.controls.scaled.cx.shape[0], 2)
)
ctrl_cx = sym_qv[:, 1] if nlp.control_type == ControlType.LINEAR_CONTINUOUS else nlp.controls.scaled.cx
qv_init_w_algebraic = (
nlp.algebraic_states["q_v"].cx
if "q_v" in nlp.algebraic_states.keys()
else DM.zeros(nlp.model.nb_dependent_joints, 1)
)

lagrange_multipliers_plot_function = Function(
"lagrange_multipliers_function",
[
time_span_sym,
nlp.states.scaled.cx,
nlp.controls.scaled.cx,
sym_qv,
nlp.parameters.scaled.cx,
nlp.algebraic_states.scaled.cx,
nlp.numerical_timeseries.cx,
Expand All @@ -1333,8 +1369,11 @@ def configure_lagrange_multipliers_function(ocp, nlp: NpArrayDictOptional, **ext
nlp.model.compute_the_lagrangian_multipliers()(
nlp.states.scaled["q_u"].cx,
nlp.states.scaled["qdot_u"].cx,
DM.zeros(nlp.model.nb_dependent_joints, 1),
DynamicsFunctions.get(nlp.controls["tau"], nlp.controls.scaled.cx),
qv_init_w_algebraic,
DynamicsFunctions.get(
nlp.controls["tau"],
ctrl_cx,
),
)
],
["t_span", "x", "u", "p", "a", "d"],
Expand All @@ -1360,7 +1399,7 @@ def configure_lagrange_multipliers_function(ocp, nlp: NpArrayDictOptional, **ext
)

nlp.plot["lagrange_multipliers"] = CustomPlot(
lambda t0, phases_dt, node_idx, x, u, p, a, d: nlp.lagrange_multipliers_function(
lambda t0, phases_dt, node_idx, x, u, p, a, d: lagrange_multipliers_plot_function(
np.concatenate([t0, t0 + phases_dt[nlp.phase_idx]]), x, u, p, a, d
),
plot_type=PlotType.INTEGRATED,
Expand Down
1 change: 1 addition & 0 deletions bioptim/examples/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
("Example simulation", "example_simulation.py"),
("Example cyclic movement", "example_cyclic_movement.py"),
("Example constraint weight", "custom_constraint_weights.py"),
("Example Pinocchio", "example_pinocchio.py"),
("How to plot", "how_to_plot.py"),
]
),
Expand Down
16 changes: 9 additions & 7 deletions bioptim/examples/getting_started/basic_ocp.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,7 @@ def main():
ocp.print(to_console=False, to_graph=False)

# --- Solve the ocp --- #
# Default is OnlineOptim.MULTIPROCESS on Linux, OnlineOptim.MULTIPROCESS_SERVER on Windows and None on MacOS
# To see the graphs on MacOS, one must run the server manually (see resources/plotting_server.py)
# Default is OnlineOptim.MULTIPROCESS_SERVER on all platforms.
solver = Solver.IPOPT(online_optim=OnlineOptim.DEFAULT)

# # Show the constraints Jacobian sparsity
Expand All @@ -180,13 +179,16 @@ def main():
sol.print_cost()
# sol.graphs(show_bounds=True, save_name="results.png")

# --- Animate the solution --- #
viewer = "bioviz"
# viewer = "pyorerun"
sol.animate(n_frames=0, viewer=viewer, show_now=True)
# # --- Animate the solution --- #
# # To animate the solution, we can use the animate function. Uncomment the current block
# # to see the animation.
# # 'bioviz' must be installed to use the bioviz viewer.
# # Similarly, 'pyorerun' must be installed to use the pyorerun viewer.
# viewer = "bioviz" # "pyorerun"
# sol.animate(n_frames=0, viewer=viewer, show_now=True)

# # --- Saving the solver's output after the optimization --- #
# Here is an example of how we recommend to save the solution. Please note that sol.ocp is not picklable and that sol will be loaded using the current bioptim version, not the version at the time of the generation of the results.
# # Here is an example of how we recommend to save the solution. Please note that sol.ocp is not picklable and that sol will be loaded using the current bioptim version, not the version at the time of the generation of the results.
# import pickle
# import git
# from datetime import date
Expand Down
Loading