{"id":51465923,"url":"https://github.com/gbionics/adam","last_synced_at":"2026-07-06T11:00:45.118Z","repository":{"id":37094132,"uuid":"370610855","full_name":"gbionics/adam","owner":"gbionics","description":"adam implements a collection of algorithms for calculating rigid-body dynamics in Jax, CasADi, PyTorch, and Numpy.","archived":false,"fork":false,"pushed_at":"2026-05-08T15:01:49.000Z","size":2583,"stargazers_count":217,"open_issues_count":11,"forks_count":29,"subscribers_count":12,"default_branch":"main","last_synced_at":"2026-05-08T17:06:32.835Z","etag":null,"topics":["adam-robotics","automatic-differentiation","casadi","jax","motion-planning","numpy","optimization","python","pytorch","reinforcement-learning","rigid-body-dynamics","robotics","urdf"],"latest_commit_sha":null,"homepage":"https://adam-docs.readthedocs.io/en/latest/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gbionics.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-05-25T07:55:26.000Z","updated_at":"2026-05-07T08:19:50.000Z","dependencies_parsed_at":"2026-05-08T17:02:59.570Z","dependency_job_id":null,"html_url":"https://github.com/gbionics/adam","commit_stats":{"total_commits":449,"total_committers":10,"mean_commits":44.9,"dds":"0.16926503340757237","last_synced_commit":"7c855ca5466e385caae188d50b964ef34fb4b089"},"previous_names":["ami-iit/adam"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/gbionics/adam","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbionics%2Fadam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbionics%2Fadam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbionics%2Fadam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbionics%2Fadam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gbionics","download_url":"https://codeload.github.com/gbionics/adam/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gbionics%2Fadam/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35187632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-06T02:00:07.184Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adam-robotics","automatic-differentiation","casadi","jax","motion-planning","numpy","optimization","python","pytorch","reinforcement-learning","rigid-body-dynamics","robotics","urdf"],"created_at":"2026-07-06T11:00:29.118Z","updated_at":"2026-07-06T11:00:45.099Z","avatar_url":"https://github.com/gbionics.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🤖 adam\n\n[![adam](https://github.com/ami-iit/adam/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/ami-iit/adam/actions/workflows/tests.yml)\n[![](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](https://github.com/ami-iit/adam/blob/main/LICENSE)\n[![DOI](https://zenodo.org/badge/370610855.svg)](https://doi.org/10.5281/zenodo.18232772)\n\n\n**Automatic Differentiation for rigid-body-dynamics Algorithms**\n\n**adam** computes rigid-body dynamics for floating-base robots. Built on Featherstone's algorithms and available across multiple backends:\n\n- 🔥 **JAX** – compile, vectorize, and differentiate with XLA\n- 🎯 **CasADi** – symbolic computation for optimization and control\n- 🔦 **PyTorch** – GPU acceleration and batched operations\n- 🐍 **NumPy** – simple numerical evaluation\n\nAll backends share the same interface and produce numerically consistent results, letting you pick the tool that fits your use case.\n\n## 📦 Installation\n\n### With pip\n\n```bash\n# JAX backend\npip install adam-robotics[jax]\n\n# CasADi backend\npip install adam-robotics[casadi]\n\n# PyTorch backend\npip install adam-robotics[pytorch]\n\n# MuJoCo support\npip install adam-robotics[mujoco]\n\n# OpenUSD support\npip install adam-robotics[usd]\n\n# Visualization support\npip install adam-robotics[visualization]\n\n# All backends\npip install adam-robotics[all]\n```\n\n### With conda\n\n```bash\n# CasADi backend\nconda create -n adamenv -c conda-forge adam-robotics-casadi\n\n# JAX backend (Linux/macOS only)\nconda create -n adamenv -c conda-forge adam-robotics-jax\n\n# PyTorch backend (Linux/macOS only)\nconda create -n adamenv -c conda-forge adam-robotics-pytorch\n\n# OpenUSD support\nconda install -n adamenv -c conda-forge openusd\n\n# All backends (Linux/macOS only)\nconda create -n adamenv -c conda-forge adam-robotics-all\n```\n\n### From source\n\n```bash\ngit clone https://github.com/ami-iit/adam.git\ncd adam\npip install .[jax]  # or [casadi], [pytorch], [mujoco], [usd], [visualization], [all]\n```\n\n## 🚀 Quick Start\n\nLoad a robot model and compute dynamics quantities:\n\n### JAX\n\n\u003e [!NOTE]\n\u003e Check the [JAX installation guide](https://jax.readthedocs.io/en/latest/installation.html)\n\n```python\nimport adam\nfrom adam.jax import KinDynComputations\nimport icub_models\nimport numpy as np\nimport jax.numpy as jnp\nfrom jax import jit, vmap\n\n# if you want to icub-models https://github.com/robotology/icub-models to retrieve the urdf\nmodel_path = icub_models.get_model_file(\"iCubGazeboV2_5\")\n# The joint list\njoints_name_list = [\n    'torso_pitch', 'torso_roll', 'torso_yaw', 'l_shoulder_pitch',\n    'l_shoulder_roll', 'l_shoulder_yaw', 'l_elbow', 'r_shoulder_pitch',\n    'r_shoulder_roll', 'r_shoulder_yaw', 'r_elbow', 'l_hip_pitch', 'l_hip_roll',\n    'l_hip_yaw', 'l_knee', 'l_ankle_pitch', 'l_ankle_roll', 'r_hip_pitch',\n    'r_hip_roll', 'r_hip_yaw', 'r_knee', 'r_ankle_pitch', 'r_ankle_roll'\n]\n\nkinDyn = KinDynComputations(model_path, joints_name_list)\n# Set velocity representation (3 options available):\n# 1. MIXED_REPRESENTATION (default) - time derivative of base origin position (expressed in world frame) + world-frame angular velocity\nkinDyn.set_frame_velocity_representation(adam.Representations.MIXED_REPRESENTATION)\n# 2. BODY_FIXED_REPRESENTATION - both linear \u0026 angular velocity in body frame\n# kinDyn.set_frame_velocity_representation(adam.Representations.BODY_FIXED_REPRESENTATION)\n# 3. INERTIAL_FIXED_REPRESENTATION - world-frame linear \u0026 angular velocity\n# kinDyn.set_frame_velocity_representation(adam.Representations.INERTIAL_FIXED_REPRESENTATION)\n\nw_H_b = np.eye(4)\njoints = np.ones(len(joints_name_list))\nM = kinDyn.mass_matrix(w_H_b, joints)\nprint(M)\nw_H_f = kinDyn.forward_kinematics('frame_name', w_H_b, joints)\n\n# JAX functions can also be jitted!\n# For example:\n\ndef frame_forward_kinematics(w_H_b, joints):\n    # This is needed since str is not a valid JAX type\n    return kinDyn.forward_kinematics('frame_name', w_H_b, joints)\n\njitted_frame_fk = jit(frame_forward_kinematics)\nw_H_f = jitted_frame_fk(w_H_b, joints)\n\n# JAX natively supports batching\njoints_batch = jnp.tile(joints, (1024, 1))\nw_H_b_batch = jnp.tile(w_H_b, (1024, 1, 1))\nw_H_f_batch = kinDyn.forward_kinematics('frame_name', w_H_b_batch, joints_batch)\n```\n\n\u003e [!NOTE]\n\u003e The first call of the jitted function can be slow, since JAX needs to compile the function. Then it will be faster!\n\n### CasADi\n\n```python\nimport casadi as cs\nimport adam\nfrom adam.casadi import KinDynComputations\nimport icub_models\nimport numpy as np\n\n# if you want to icub-models https://github.com/robotology/icub-models to retrieve the urdf\nmodel_path = icub_models.get_model_file(\"iCubGazeboV2_5\")\n# The joint list\njoints_name_list = [\n    'torso_pitch', 'torso_roll', 'torso_yaw', 'l_shoulder_pitch',\n    'l_shoulder_roll', 'l_shoulder_yaw', 'l_elbow', 'r_shoulder_pitch',\n    'r_shoulder_roll', 'r_shoulder_yaw', 'r_elbow', 'l_hip_pitch', 'l_hip_roll',\n    'l_hip_yaw', 'l_knee', 'l_ankle_pitch', 'l_ankle_roll', 'r_hip_pitch',\n    'r_hip_roll', 'r_hip_yaw', 'r_knee', 'r_ankle_pitch', 'r_ankle_roll'\n]\n\nkinDyn = KinDynComputations(model_path, joints_name_list)\n# Set velocity representation (3 options available):\n# 1. MIXED_REPRESENTATION (default) - time derivative of position + world-frame angular velocity\nkinDyn.set_frame_velocity_representation(adam.Representations.MIXED_REPRESENTATION)\n# 2. BODY_FIXED_REPRESENTATION - both linear \u0026 angular velocity in body frame\n# kinDyn.set_frame_velocity_representation(adam.Representations.BODY_FIXED_REPRESENTATION)\n# 3. INERTIAL_FIXED_REPRESENTATION - world-frame linear \u0026 angular velocity\n# kinDyn.set_frame_velocity_representation(adam.Representations.INERTIAL_FIXED_REPRESENTATION)\n\nw_H_b = np.eye(4)\njoints = np.ones(len(joints_name_list))\nM = kinDyn.mass_matrix_fun()\nprint(M(w_H_b, joints))\n\n# If you want to use the symbolic version\nw_H_b = cs.SX.eye(4)\njoints = cs.SX.sym('joints', len(joints_name_list))\nM = kinDyn.mass_matrix_fun()\nprint(M(w_H_b, joints))\n\n# This is usable also with casadi.MX\nw_H_b = cs.MX.eye(4)\njoints = cs.MX.sym('joints', len(joints_name_list))\nM = kinDyn.mass_matrix_fun()\nprint(M(w_H_b, joints))\n```\n\n### PyTorch\n\n```python\nimport adam\nfrom adam.pytorch import KinDynComputations\nimport icub_models\nimport numpy as np\n\n# if you want to icub-models https://github.com/robotology/icub-models to retrieve the urdf\nmodel_path = icub_models.get_model_file(\"iCubGazeboV2_5\")\n# The joint list\njoints_name_list = [\n    'torso_pitch', 'torso_roll', 'torso_yaw', 'l_shoulder_pitch',\n    'l_shoulder_roll', 'l_shoulder_yaw', 'l_elbow', 'r_shoulder_pitch',\n    'r_shoulder_roll', 'r_shoulder_yaw', 'r_elbow', 'l_hip_pitch', 'l_hip_roll',\n    'l_hip_yaw', 'l_knee', 'l_ankle_pitch', 'l_ankle_roll', 'r_hip_pitch',\n    'r_hip_roll', 'r_hip_yaw', 'r_knee', 'r_ankle_pitch', 'r_ankle_roll'\n]\n\nkinDyn = KinDynComputations(model_path, joints_name_list)\n# choose the representation you want to use the body fixed representation\nkinDyn.set_frame_velocity_representation(adam.Representations.BODY_FIXED_REPRESENTATION)\n# or, if you want to use the mixed representation (that is the default)\nkinDyn.set_frame_velocity_representation(adam.Representations.MIXED_REPRESENTATION)\nw_H_b = np.eye(4)\njoints = np.ones(len(joints_name_list))\nM = kinDyn.mass_matrix(w_H_b, joints)\nprint(M)\n```\n\n### PyTorch Batched\n\nUse `pytorch.KinDynComputations` to process also multiple configurations.\n\n\u003e [!NOTE]\n\u003e There is a class `pytorch.KinDynComputationsBatch` that has the functionality of `pytorch.KinDynComputations`. It exists to avoid API changes in existing code. New users should prefer `pytorch.KinDynComputations` for both single and batched computations.\n\n\n```python\nimport adam\nfrom adam.pytorch import KinDynComputations\nimport icub_models\n\n# if you want to icub-models\nmodel_path = icub_models.get_model_file(\"iCubGazeboV2_5\")\n# The joint list\njoints_name_list = [\n    'torso_pitch', 'torso_roll', 'torso_yaw', 'l_shoulder_pitch',\n    'l_shoulder_roll', 'l_shoulder_yaw', 'l_elbow', 'r_shoulder_pitch',\n    'r_shoulder_roll', 'r_shoulder_yaw', 'r_elbow', 'l_hip_pitch', 'l_hip_roll',\n    'l_hip_yaw', 'l_knee', 'l_ankle_pitch', 'l_ankle_roll', 'r_hip_pitch',\n    'r_hip_roll', 'r_hip_yaw', 'r_knee', 'r_ankle_pitch', 'r_ankle_roll'\n]\n\nkinDyn = KinDynComputations(model_path, joints_name_list)\n# choose the representation you want to use the body fixed representation\nkinDyn.set_frame_velocity_representation(adam.Representations.BODY_FIXED_REPRESENTATION)\n# or, if you want to use the mixed representation (that is the default)\nkinDyn.set_frame_velocity_representation(adam.Representations.MIXED_REPRESENTATION)\nw_H_b = np.eye(4)\njoints = np.ones(len(joints_name_list))\n\nnum_samples = 1024\nw_H_b_batch = torch.tensor(np.tile(w_H_b, (num_samples, 1, 1)), dtype=torch.float32)\njoints_batch = torch.tensor(np.tile(joints, (num_samples, 1)), dtype=torch.float32)\n\nM = kinDyn.mass_matrix(w_H_b_batch, joints_batch)\nw_H_f = kinDyn.forward_kinematics('frame_name', w_H_b_batch, joints_batch)\n```\n\n### MuJoCo\n\nadam supports loading models directly from [MuJoCo](https://mujoco.org/) `MjModel` objects. This is useful when working with MuJoCo simulations or models from [robot_descriptions](https://github.com/robot-descriptions/robot_descriptions.py).\n\n```python\nimport mujoco\nimport numpy as np\nfrom adam import Representations\nfrom adam.numpy import KinDynComputations\n\n# Load a MuJoCo model (e.g., from robot_descriptions)\nfrom robot_descriptions.loaders.mujoco import load_robot_description\nmj_model = load_robot_description(\"g1_mj_description\")\n\n# Create KinDynComputations directly from MuJoCo model\nkinDyn = KinDynComputations.from_mujoco_model(mj_model)\n\n# Set velocity representation (default is mixed)\nkinDyn.set_frame_velocity_representation(Representations.MIXED_REPRESENTATION)\n\n# Set gravity to match MuJoCo settings\nkinDyn.g = np.concatenate([mj_model.opt.gravity, np.zeros(3)])\n\n# Create MuJoCo data and set state\nmj_data = mujoco.MjData(mj_model)\nmj_data.qpos[:] = your_qpos  # Your configuration\nmj_data.qvel[:] = your_qvel  # Your velocities\nmujoco.mj_forward(mj_model, mj_data)\n\n# Extract base transform from MuJoCo state (for floating-base robots)\nfrom scipy.spatial.transform import Rotation as R\nbase_rot = R.from_quat(mj_data.qpos[3:7], scalar_first=True).as_matrix()\nbase_pos = mj_data.qpos[0:3]\nw_H_b = np.eye(4)\nw_H_b[:3, :3] = base_rot\nw_H_b[:3, 3] = base_pos\n\n# Joint positions (excluding free joint).\n# Be sure the serialization between mujoco and adam is the same\njoints = mj_data.qpos[7:]\n\n# Compute dynamics quantities\nM = kinDyn.mass_matrix(w_H_b, joints)\ncom_pos = kinDyn.CoM_position(w_H_b, joints)\nJ = kinDyn.jacobian('frame_name', w_H_b, joints)\n```\n\n\u003e [!NOTE]\n\u003e When using `from_mujoco_model`, adam automatically extracts the joint names from the MuJoCo model. You can also specify `use_mujoco_actuators=True` to use actuator names instead of joint names.\n\n\u003e [!WARNING]\n\u003e MuJoCo uses a different velocity representation for the floating base. The free joint velocity in MuJoCo is `[I \\dot{p}_B, B \\omega_B]`, while mixed representation uses `[I \\dot{p}_B, I \\omega_B]`. Make sure to handle this transformation when comparing with MuJoCo computations.\n\n### OpenUSD\n\nadam supports loading robot models directly from OpenUSD files and exporting models to OpenUSD.\n\n**Loading directly from a USD file:**\n\n```python\nimport numpy as np\nfrom adam import Representations\nfrom adam.numpy import KinDynComputations\n\n# Load directly from any existing USD file\nkinDyn = KinDynComputations.from_usd(\n    \"robot.usd\",\n    robot_prim_path=\"/Robot\",\n    joints_name_list=[\"joint_1\", \"joint_2\"],\n)\nkinDyn.set_frame_velocity_representation(Representations.MIXED_REPRESENTATION)\n\n# Compute quantities as usual\nw_H_b = np.eye(4)\nq = np.zeros(kinDyn.NDoF)\nM = kinDyn.mass_matrix(w_H_b, q)\ncom = kinDyn.CoM_position(w_H_b, q)\n```\n\n**Exporting a model to USD** (e.g. to convert a URDF to USD):\n\n```python\nfrom adam.model import Model, build_model_factory\nfrom adam.numpy.numpy_like import SpatialMath\n\nmodel_path = \"robot.urdf\"\njoints_name_list = [\"joint_1\", \"joint_2\"]\n\nfactory = build_model_factory(description=model_path, math=SpatialMath())\nmodel = Model.build(factory=factory, joints_name_list=joints_name_list)\n\n# Export to USD\nmodel.to_usd(\"robot.usd\", robot_prim_path=\"/Robot\")\n```\n\n### Visualization\n\nadam also provides a lightweight visualization layer based on [viser](https://viser.studio/).\nIt works with the same normalized model API, so URDF, MuJoCo, and USD models can all be rendered through the same interface.\n\nFor quick inspection from the terminal, use the bundled viewer command:\n\n```bash\nadam-model-view --urdf path/to/robot.urdf\nadam-model-view --mujoco path/to/model.xml\nadam-model-view --usd path/to/robot.usd --robot-prim-path /Robot\n```\n\n```python\nimport numpy as np\nimport icub_models\nfrom adam.numpy import KinDynComputations\nfrom adam.visualization import Visualizer\n\nkindyn = KinDynComputations.from_urdf(\n    icub_models.get_model_file(\"iCubGazeboV2_5\")\n)\n\nvisualizer = Visualizer(\n    world_axes=True,\n    ground=True,\n    camera_position=(2.5, -2.0, 1.5),\n    camera_look_at=(0.0, 0.0, 0.6),\n)\n\nrobot = visualizer.add_model(kindyn, root_name=\"/icub\")\n\nw_H_b = np.eye(4)\nw_H_b[2, 3] = 0.6\nq = np.zeros(kindyn.NDoF)\nrobot.update(w_H_b, q)\nrobot.add_joint_sliders(folder_name=\"iCub\")\n```\n\nWith other model sources, only the loader changes:\n\n```python\n# MuJoCo\nkindyn = KinDynComputations.from_mujoco_model(mj_model)\n\n# USD\nkindyn = KinDynComputations.from_usd(\"robot.usd\", robot_prim_path=\"/Robot\")\n```\n\nBatched visualization is available through the same `ModelHandle` API by passing\n`num_instances` to `add_model()`. The model is rendered with viser batched meshes,\nand each `update()` call accepts base transforms with shape `(B, 4, 4)` and joint\npositions with shape `(B, N)`:\n\n```python\nnum_instances = 16\nrobot = visualizer.add_model(\n    kindyn,\n    root_name=\"/g1_batch\",\n    num_instances=num_instances,\n)\n\nw_H_b = np.repeat(np.eye(4)[None, :, :], num_instances, axis=0)\nq = np.zeros((num_instances, kindyn.NDoF))\nrobot.update(w_H_b, q)\n```\n\nFor a ready-to-run MuJoCo example with a batch of Unitree G1 robots:\n\n```bash\npython examples/visualization/visualize_g1_batch.py\n```\n\nThe batched example animates `left_hip_pitch_joint` by default with a phase offset\nper instance. Frames and joint sliders are scalar-model conveniences and are not\nenabled for batched models.\n\nExamples are available in:\n\n- `examples/visualization/visualize_mujoco.py`\n- `examples/visualization/visualize_g1_batch.py`\n- `examples/visualization/visualize_usd.py`\n- `examples/visualization/visualize_multi_robot.py`\n- `examples/visualization/visualize_urdf.py`\n\n### Configurable Floating Base\n\nBy default adam uses the root link of the URDF as the floating base. You can choose any other link as the floating base at construction time or at runtime:\n\n```python\nfrom adam.numpy import KinDynComputations\n\n# Construction-time: use \"l_ankle_2\" as the floating base\nkinDyn = KinDynComputations(model_path, joints_name_list, root_link=\"l_ankle_2\")\n\n# Runtime setter (rebuilds the kinematic tree)\nkinDyn.set_root_link(\"chest\")\n```\n\nadam re-roots the kinematic tree internally by reversing the joints along the path from the new root to the original URDF root. All dynamics quantities (mass matrix, Jacobians, bias forces, …) are then consistent with the new floating base. Results match iDynTree's `setFloatingBase` API.\n\n\u003e [!IMPORTANT]\n\u003e **Joint serialization is independent of the floating base.** The order of joints in the `joints` vector is fixed by `joints_name_list` at construction time and never changes — only the *base state* inputs (`w_H_b` and base velocity) reflect the new floating base.\n\n\u003e [!NOTE]\n\u003e `root_link` must be a **link** name, not a frame name. Passing a frame name raises a `ValueError` listing valid link names. Frames remain valid as targets for forward kinematics and Jacobians.\n\n### Inverse Kinematics\n\n```python\nimport casadi as cs\nimport numpy as np\nimport adam\nfrom adam.casadi import KinDynComputations\nfrom adam.casadi.inverse_kinematics import InverseKinematics, TargetType\n\n# Load model\nmodel_path = ...\njoints_name_list = [...]\n\n# Create IK solver\nik = InverseKinematics(model_path, joints_name_list)\nik.add_target(\"l_sole\", target_type=TargetType.POSE, as_soft_constraint=True, weight=1.0)\n\n# Update target and solve\ndesired_position = np.array([0.3, 0.2, 1.0])\ndesired_orientation = np.eye(3)\nik.update_target(\"l_sole\", (desired_position, desired_orientation))\nik.solve()\n\n# Get solution\nw_H_b_sol, q_sol = ik.get_solution()\nprint(\"Base pose:\\n\", w_H_b_sol)\nprint(\"Joint values:\\n\", q_sol)\n```\n\n## 📚 Features\n\n- **Kinematics**: Forward kinematics, Jacobians (frame and base)\n- **Dynamics**: Mass matrix, Coriolis/centrifugal forces and gravity, Articulated body algorithm\n- **Centroidal**: Centroidal momentum matrix and derivatives\n- **Configurable floating base**: Any link can be set as the floating base\n- **Differentiation**: Get gradients, Jacobians, and Hessians automatically\n- **Symbolic**: Build computation graphs with CasADi for optimization\n- **Batched**: Process multiple configurations in parallel with PyTorch\n- **Visualization**: Render URDF, MuJoCo, and USD robot models with viser\n\n## 📖 Documentation\n\nSee the [full documentation](https://adam-robotics.readthedocs.io/en/latest/) for detailed API reference, more examples, and theory.\n\n## 🧪 Testing\n\nRun tests to verify installation:\n\n```bash\npip install .[test]  # Install test dependencies\npytest tests/\n```\n\nSee `tests/` folder for comprehensive examples across all backends.\n\n## 🤝 Contributing\n\nFound a bug or have a feature idea? Open an [issue](https://github.com/ami-iit/adam/issues) or submit a [pull request](https://github.com/ami-iit/adam/pulls)! 🚀\n\n\u003e [!WARNING]\n\u003e This is a project under active development. API may change.\n\n## 📄 License\n\nBSD 3-Clause License – see [LICENSE](LICENSE) file.\n\n## 🙏 Acknowledgments\n\nBuilt on [Roy Featherstone's Rigid Body Dynamics Algorithms](https://link.springer.com/book/10.1007/978-1-4899-7560-7) and references like [Traversaro's A Unified View of the Equations of Motion](https://traversaro.github.io/traversaro-phd-thesis/traversaro-phd-thesis.pdf).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgbionics%2Fadam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgbionics%2Fadam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgbionics%2Fadam/lists"}