BAM fits real servo friction so a policy trained in simulation survives the robot
Identify and simulate extended friction models for servo-actuators
At a glance
- What is it?
- BAM, Better Actuator Models, is a Python library for identifying extended friction models of servo actuators from recorded trajectories and replaying them in MuJoCo CPU and MuJoCo Warp. It ships identified parameters for seven common servos and depends only on numpy and colorama at its core.
- Who is it for?
- Adopt BAM if you train reinforcement learning policies in simulation and transfer them to a real robot, since the friction model is where a Coulomb-Viscous assumption breaks the transfer. Skip it if you are not using MuJoCo, because the runtime integration is MuJoCo specific, and skip it if you cannot run the identification pipeline, since the library's own models cover only the servos it lists.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 25 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why Coulomb-Viscous friction breaks sim-to-real transfer
The premise is stated at the top of the README. Accurate models of servo actuators are essential for the simulation of robotic systems, and it is particularly important while performing Reinforcement Learning on real robots, because the precision of the model impacts directly the transferability of the learned policy. The friction model generally implemented in widely used simulators like MuJoCo or IsaacGym is the Coulomb-Viscous one, and the README calls it too simplistic to accurately represent complex friction phenomena such as Stribeck effects, load-dependence or quadratic effects, with a paper linked for the details. That is the gap BAM addresses. A policy trained against a friction law that does not exist in the physical joint will be tuned to compensate for a mismatch that the real hardware does not have, and the usual result is a policy that looks fine in simulation and fails on the bench. The project frames this as a modelling problem rather than a control algorithm problem, and that framing is what makes the identification pipeline the centre of the library rather than an afterthought.
The four things BAM actually delivers
The README lists four contributions. The first is an identification pipeline to fit friction models from recorded trajectories, so a model is derived from your hardware rather than guessed. The second is a set of extended friction models that capture complex friction phenomena, the ones the Coulomb-Viscous law misses. The third is a library of identified models for common servos, which removes the need to run identification at all if your hardware is in the list: Dynamixel MX-64, Dynamixel MX-106, Dynamixel XL-320, Dynamixel XL330-M288-T, eRob80:50, eRob80:100 and Feetech STS3215. The fourth is a simple API to use those models in MuJoCo CPU and MuJoCo Warp. The last point is the one that decides whether the library is useful to you. A friction model you cannot plug into your simulator is a set of coefficients on a spreadsheet, and the fact that BAM targets both the CPU build of MuJoCo and the GPU path through MuJoCo Warp means the same identified parameters can be used whether your training runs on a laptop or on a GPU cluster.
Installing the package and its optional stacks
The distribution is published as better-actuator-models, with the import name kept short in the bam package directory. The project metadata fixes the interpreter range and the core dependencies.
[project]
name = "better-actuator-models"
version = "1.0.2"
requires-python = ">=3.12,<3.13"Only numpy and colorama are required, which keeps the core install light. Everything else is opt-in through extras, and the naming tells you what each one buys you. The mujoco extra adds the CPU simulator, the identification extra adds the hardware and optimisation stack (zmq, protobuf, dynamixel_sdk, rustypot, optuna, cmaes, wandb, matplotlib and PyQt5), and the mjlab extra covers the GPU path through mjlab.
mjlab = [
"mjlab>=1.3,<1.4",
"mujoco-warp>=3.7,<3.8",
"mujoco>=3.7,<3.8",
"warp-lang>=1.12,<1.13",
"scipy"
]Those pins are not arbitrary and the comment in the project file explains why. mjlab 1.3 targets the MuJoCo Warp 3.7 era and uses ls_parallel, which was removed in mujoco-warp 3.9.1, and wp.context, which was removed in warp-lang 1.15. Without matching the simulation stack to that combination, creating a Simulation raises an error about ls_parallel being removed or about the warp module having no attribute context. If you take one thing away from this file, take that: the GPU extras are version-locked as a set and mixing a newer mujoco-warp with mjlab 1.3 will fail at simulation construction rather than at install time.
Identification needs real hardware and a logging stack
The identification extra is the heaviest of the three and reveals what the pipeline involves. dynamixel_sdk and rustypot are hardware drivers, so the pipeline talks to your servos directly rather than replaying a hand-prepared file. zmq and protobuf carry the logged data, optuna and cmaes run the optimisation that fits parameters to the recorded trajectories, wandb tracks the runs, matplotlib and PyQt5 produce plots and the diagnostic interface, and scipy supports the fitting maths. This tells you two things. First, identifying your own motor is a workstation activity with the servo connected, not something you do in a container on a build server. Second, the fit is an optimisation over a parameter set, which means the identified model is only as good as the trajectory you recorded and the objective you chose, and the tooling exists so that you can look at the fit rather than trust it blindly. The repo also has a code-gen directory at the top level, which is consistent with the identified models for the listed servos being generated artefacts rather than hand-typed parameters.
Where BAM sits against the usual alternatives
The alternative is to stay inside the simulator and accept the default friction. That is what most reinforcement learning pipelines do, and the cost of that choice is exactly what BAM names: a policy that transfers badly because it learned to exploit a friction law that is not physical. A middle option is to hand-tune the friction parameters already exposed by MuJoCo, which is cheaper than running an identification pipeline and still leaves the extended phenomena out of the model. The third option is to use another physics engine with a richer joint model, which changes the actuator model but does not give you parameters fitted to your specific hardware, and it means rewriting your training stack. BAM's difference is that it does not replace the simulator, it corrects the simulator, and it makes the correction specific to your servo. The published work behind it is the ICRA 2025 paper Extended Friction Models for the Physics Simulation of Servo Actuators by Duclusaud, Passault, Padois and Ly, and the README asks that it be cited if you use the models for scientific work, with a separate software citation entry available.
Limits, versioning and the licence
Three limits are worth stating plainly. The first is the interpreter pin. requires-python is >=3.12,<3.13, so the package does not install on 3.11 or on 3.13, which is a narrow gate for a library in a research code base where the interpreter version is often shared across projects. The second is that the shared model library covers seven specific servos, and if your robot uses a different actuator you are back to running the identification pipeline with the hardware and optimisation stack. The third is that the simulator integration is MuJoCo only, in both its CPU and Warp flavours, so a team working in IsaacGym or IsaacLab cannot consume the models directly. On maintenance, the project has three releases in short succession, v1.0.0, v1.0.1 and v1.0.2, with v1.0.2 published on 2026-07-16, and the last push to the repository was on 2026-09-28, so the code is being worked on. The licence is Apache-2.0, declared in the project metadata and with the text in the LICENSE file at the repository root. Apache 2.0 grants patent rights alongside the copyright grant, which matters more for a robotics lab than for most libraries, though it also carries the requirement to preserve notices when redistributing.
Editorial conclusion
Adopt BAM if you train reinforcement learning policies in simulation and transfer them to a real robot, since the friction model is where a Coulomb-Viscous assumption breaks the transfer. Skip it if you are not using MuJoCo, because the runtime integration is MuJoCo specific, and skip it if you cannot run the identification pipeline, since the library's own models cover only the servos it lists. Before you start, confirm your Python version is 3.12, since the package requires >=3.12,<3.13, and read the mjlab dependency pins, because mjlab 1.3 needs mujoco-warp 3.7 and warp-lang 1.12 to be installed alongside it.
Frequently asked questions
What is BAM, Better Actuator Models?
BAM is a Python library dedicated to the identification and simulation of advanced actuator models for servo actuators. It proposes an identification pipeline to fit friction models from recorded trajectories and provides extended friction models that capture phenomena the usual Coulomb-Viscous law misses.
Which servos does BAM ship identified friction models for?
Dynamixel MX-64, Dynamixel MX-106, Dynamixel XL-320, Dynamixel XL330-M288-T, eRob80:50, eRob80:100 and Feetech STS3215.
What Python version and dependencies does better-actuator-models need?
The package requires Python >=3.12,<3.13 and depends on numpy and colorama at its core. Simulation and identification are optional extras: mujoco for the CPU simulator, mjlab for the GPU path, and an identification extra with zmq, protobuf, dynamixel_sdk, rustypot, optuna, cmaes, wandb, matplotlib and PyQt5.
Which MuJoCo versions work with the BAM mjlab extra?
The extra pins mjlab 1.3 with mujoco-warp 3.7 and warp-lang 1.12. The project file explains that mjlab 1.3 uses ls_parallel and wp.context, which were removed in mujoco-warp 3.9.1 and warp-lang 1.15, so mixing versions makes Simulation() raise an error.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rhoban-bam)Was this useful?