Skip to content

TAMPanda: Just Another MuJoCo Wrapper

Daniel Swoboda 3 min read
roboticstask and motion planningMuJoConeuro-symbolicopen source

A short tour of TAMPanda, now public: a MuJoCo wrapper for the Franka Panda that takes you from a symbolic plan to a physically validated, collision-free execution — so you can work on the algorithm, not the plumbing.

I’ve open-sourced TAMPanda, the task-and-motion-planning library I’ve been building in our group at RWTH Aachen (the Chair of Machine Learning and Reasoning, i6). Its own README calls it “just another MuJoCo wrapper,” which is honest and also a little self-deprecating.

The motivation is unglamorous. Going from a tidy planning benchmark to a physics simulation is a slog: before you can test a single idea you need scenes, collision detection, a grasp pipeline, inverse kinematics, and a control loop. TAMPanda is the pile of infrastructure I kept rewriting, finally packaged so the next person — usually me — can spend their time on the algorithm instead of the plumbing.

What’s in the box

At its core it drives a Franka Emika Panda (and a differential-drive mobile robot) in MuJoCo 3 — MIT-licensed, Python ≥ 3.10. The layers stack the way you’d hope:

MuJoCo render of a Franka Panda arm at a table with small objects, shown from a front and a top camera
A scene assembled with SceneBuilder — the Panda at a tabletop, front and top views.
  • Scenes — a SceneBuilder assembles environments from reusable MJCF templates at runtime, with hot-reload, and fetches ~80 YCB and ~1,000 Google Scanned Objects on demand.
  • Control & IK — gravity-compensated position control, collision detection, and differential IK via MINK.
  • Motion planning — RRT* with path smoothing in joint space, A* navigation for the mobile base, and parallelised RRT feasibility checks fast enough to shape rewards inside a learning loop.
  • Grasping — geometry-aware grasp-candidate ranking, and a PickPlaceExecutor that runs end-to-end pick-and-place with multi-candidate retry.
Six MuJoCo renders showing a Franka Panda moving along an RRT-star planned path from start to goal, in front and top views
RRT\* path snapshots between a start and goal configuration, front and top.

So a handful of lines takes you from an empty table to a placed block:

env      = builder.build_env(rate=200.0)
planner  = RRTStar(env)
executor = PickPlaceExecutor(env, planner, GraspPlanner(table_z=0.27))

ok = executor.pick("block_0",
                   env.get_object_position("block_0"),
                   env.get_object_half_size("block_0"),
                   env.get_object_orientation("block_0"))
if ok:
    executor.place("block_0", np.array([0.50, 0.25, 0.31]))
Three MuJoCo renders of a Franka Panda performing a pick-and-place: the initial scene, the block grasped, and the block placed at its target
The PickPlaceExecutor running the loop above: before, after the pick, and after the place.

The part I actually care about

The piece that makes TAMPanda more than a control sandbox is the DomainBridge. You wire any PDDL domain to the continuous stack with a few Python decorators — register predicate evaluators, action executors, and pose samplers — and then call ground_state, plan, and execute_action without writing any domain-specific glue. Planning itself goes through unified-planning, so the solver is swappable.

The detail I like most: before a symbolic action like pick(block) is committed to a plan, an ActionFeasibilityChecker validates it against the continuous planner — IK plus RRT* — so the plan can’t promise something the arm can’t actually do. That’s the same conviction I wrote about last time: keep the symbolic scaffold legible, and make the geometry answer to it rather than the other way around. TAMPanda is, in part, the tooling that lets me work that way.

For the learning side

tampanda.gym wraps any scene as a standard gymnasium.Env: configurable observation spaces (joints, end-effector pose, object poses, RGB, depth, point clouds), three action spaces (joint delta, joint target, Cartesian end-effector delta via IK), and a goal-conditioned TampandaGoalEnv with HER-compatible rewards. The DomainBridge can be plugged in as a bridge_factory, so the symbolic state shows up in info and predicate vectors can serve as structured goals. There’s a PseudoGraspWrapper for kinematic attachment, an ExpertActionWrapper for imitation learning, and a spawn-safe make_vec_env for parallel rollouts.

Scope, honestly

It’s a deliberately lightweight alternative to full TAMP systems — good for rapid prototyping, not a replacement for a production stack. Some corners are still rough (point-cloud grasping on unseen objects is a work in progress). It’s in active use for ongoing work in our group; you can read the broader research context here.

If it’s useful to you, the getting-started notebooks are the fastest way in, and there’s a bibtex entry in the README if you end up citing it. Issues and pull requests welcome — it’s only another MuJoCo wrapper, after all.