From 4e10f20be662a25c946d8b4638026c3dbafb04b9 Mon Sep 17 00:00:00 2001 From: Yuval Tassa Date: Mon, 15 Jun 2026 06:29:02 -0700 Subject: [PATCH] Fix set_to_muscle() to accept tuple arguments. Correct argument types for timeconst and range parameters in pybind11 python bindings from C arrays to std::array. Fixes #3282, #3282, #3318 Thanks to @Abzaek for original PRs PiperOrigin-RevId: 932423401 Change-Id: Ic30ba076913693f5c0e545789690e8b0fa444390 --- python/mujoco/specs.cc | 20 +++++++++++--------- python/mujoco/specs_test.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/python/mujoco/specs.cc b/python/mujoco/specs.cc index 4d5784cb..8bc0d00d 100644 --- a/python/mujoco/specs.cc +++ b/python/mujoco/specs.cc @@ -1577,20 +1577,22 @@ PYBIND11_MODULE(_specs, m) { py::arg("diameter") = -1); mjsActuator.def( "set_to_muscle", - [](raw::MjsActuator* self, double timeconst[2], double tausmooth, - double range[2], double force, double scale, double lmin, double lmax, - double vmax, double fpmax, double fvmax) { + [](raw::MjsActuator* self, std::array timeconst, + double tausmooth, std::array range, double force, + double scale, double lmin, double lmax, double vmax, double fpmax, + double fvmax) { std::string err = - mjs_setToMuscle(self, timeconst, tausmooth, range, force, scale, - lmin, lmax, vmax, fpmax, fvmax); + mjs_setToMuscle(self, timeconst.data(), tausmooth, range.data(), + force, scale, lmin, lmax, vmax, fpmax, fvmax); if (!err.empty()) { throw pybind11::value_error(err); } }, - py::arg("timeconst") = -1, py::arg("tausmooth"), - py::arg("range") = std::array{-1, -1}, py::arg("force") = -1, - py::arg("scale") = -1, py::arg("lmin") = -1, py::arg("lmax") = -1, - py::arg("vmax") = -1, py::arg("fpmax") = -1, py::arg("fvmax") = -1); + py::arg("timeconst") = std::array{-1, -1}, + py::arg("tausmooth"), py::arg("range") = std::array{-1, -1}, + py::arg("force") = -1, py::arg("scale") = -1, py::arg("lmin") = -1, + py::arg("lmax") = -1, py::arg("vmax") = -1, py::arg("fpmax") = -1, + py::arg("fvmax") = -1); mjsActuator.def( "set_to_adhesion", [](raw::MjsActuator* self, double gain) { diff --git a/python/mujoco/specs_test.py b/python/mujoco/specs_test.py index 047584a3..17b803c8 100644 --- a/python/mujoco/specs_test.py +++ b/python/mujoco/specs_test.py @@ -1602,6 +1602,38 @@ class SpecsTest(absltest.TestCase): self.assertEqual(actuator.gaintype, mujoco.mjtGain.mjGAIN_DCMOTOR) self.assertEqual(actuator.biastype, mujoco.mjtBias.mjBIAS_DCMOTOR) + actuator = spec.add_actuator() + actuator.set_to_muscle(tausmooth=0.1) + self.assertEqual(actuator.dyntype, mujoco.mjtDyn.mjDYN_MUSCLE) + self.assertEqual(actuator.gaintype, mujoco.mjtGain.mjGAIN_MUSCLE) + self.assertEqual(actuator.biastype, mujoco.mjtBias.mjBIAS_MUSCLE) + self.assertEqual(actuator.dynprm[2], 0.1) + + actuator.set_to_muscle( + timeconst=[0.02, 0.05], + tausmooth=0.2, + range=[0.8, 1.2], + force=5.0, + scale=250.0, + lmin=0.6, + lmax=1.7, + vmax=1.8, + fpmax=1.4, + fvmax=1.5, + ) + self.assertEqual(actuator.dynprm[0], 0.02) + self.assertEqual(actuator.dynprm[1], 0.05) + self.assertEqual(actuator.dynprm[2], 0.2) + self.assertEqual(actuator.gainprm[0], 0.8) + self.assertEqual(actuator.gainprm[1], 1.2) + self.assertEqual(actuator.gainprm[2], 5.0) + self.assertEqual(actuator.gainprm[3], 250.0) + self.assertEqual(actuator.gainprm[4], 0.6) + self.assertEqual(actuator.gainprm[5], 1.7) + self.assertEqual(actuator.gainprm[6], 1.8) + self.assertEqual(actuator.gainprm[7], 1.4) + self.assertEqual(actuator.gainprm[8], 1.5) + def test_bad_contact_sensor(self): test_cases = [ dict(