The whole loop in one minute
An environment is a repeatable control problem. At every control step, your code receives numbers describing the robot, chooses an action, and receives a reward describing how useful that action was.
reset()/step() interface. First make the loop run; train only after the signals make sense.Install the package
LavenderSim supports Python 3.9+ and publishes native wheels for Linux x86-64, macOS Intel, and macOS arm64.
python -m pip install lavendersimVerify both the Python package and native engine:
python -c "import lavendersim; print(lavendersim.__version__)"
python -c "from lavendersim.env import list_envs; print(len(list_envs()))"Develop from a source checkout
git clone https://github.com/cloneofsimo/lavendersim.git
cd lavendersim
python3 -m venv .venv
.venv/bin/pip install -e '.[dev,rl]'
./build_native.shA source build needs CMake and a C++17 compiler. The editable install keeps Python changes live while build_native.sh rebuilds the engine.
Run one episode
Save this as first_episode.py. The zero action is deliberately boring: it validates scene creation, native stepping, observations, and termination without needing a checkpoint.
import numpy as np
from lavendersim.env import make
env = make("CartPoleBalance-v0", seed=7)
observation, info = env.reset(seed=7)
episode_return = 0.0
for step in range(180):
action = np.zeros(env.action_space.shape, dtype=np.float32)
observation, reward, terminated, truncated, info = env.step(action)
episode_return += reward
if terminated or truncated:
break
print("observation:", observation.shape)
print("action:", env.action_space.shape)
print("steps:", step + 1)
print("return:", round(episode_return, 2))
print("tracking:", round(float(info["tracking"]), 3))
env.close()You should see an observation shape of (12,), an action shape of (1,), finite reward, and at most 180 steps. Exact reward can vary with package version.
Understand the return values
| Value | Meaning | Typical question |
|---|---|---|
observation | Flat float32 array consumed by your controller. | What can the policy sense? |
reward | Task-specific score for the last action. | Was that action useful? |
terminated | Success or physical failure ended the episode. | Did the task reach a terminal outcome? |
truncated | The configured time horizon ended the episode. | Did time simply run out? |
info | Debug metrics such as error, tracking, and contacts. | Why did reward change? |
Try different actions safely
Every continuous environment has a bounded Box. Inspect its limits and sample with the environment’s seeded generator:
print(env.action_space.low)
print(env.action_space.high)
action = env.action_space.sample(env.rng)
observation, reward, terminated, truncated, info = env.step(action)During debugging, start with zeros or small actions. Large random actions are useful for robustness tests, but they can make articulated robots fall immediately.
Try the examples
python examples/envs/list_envs.py
python examples/envs/rover_waypoint.py --steps 300 --headless
python examples/envs/cartpole_balance.py --steps 600 --web--headless runs as quickly as possible. --web starts the live viewer on port 8765. The example scripts are small on purpose—copy one when starting a task.
Choose your next step
Common problems
Native library not found
Install a platform wheel, or run ./build_native.sh in a source checkout. Confirm that your virtual environment and python command refer to the same interpreter.
Why is the policy doing nothing?
The examples intentionally use safe zero-action or deterministic smoke controllers. Train PPO or load a compatible checkpoint to obtain learned behavior.
The episode ends immediately
Print terminated, truncated, and info separately. A physical failure is different from reaching the time limit; aggressive random actions often trigger the former.
Is this MuJoCo compatible?
No. The API borrows useful simulation concepts, but is intentionally Python-first and has no MJCF importer. Treat physics results as experimental.
