Skip to main content

EvcRL 0.0.1

A Gymnasium environment for longitudinal electric-vehicle eco-driving with a procedural RGB camera, a sourced energy model (regenerative braking, load-dependent efficiency, pack acceptance ceiling), a camera-event memory and a sampled jerk-bounded execution layer. It packages the environment used in the accompanying manuscript (TIV v25/v26) so that policies, detectors and executors can be exchanged against a fixed, versioned reference.

Installing and importing the package needs NumPy, Pillow and Gymnasium only. No Torch and no CUDA are imported; the base environment runs on a CPU laptop.

capability this release
environments EvcRL-Camera-v0 (4 km, RGB 96×160 at 2 Hz), EvcRL-Structured-v0 (20 km, 13-dim structured), EvcRL-StructuredMini-v0 (4 km structured)
perception procedural camera; signals visible within 200 m of the stop line; curve-warning sign 400 m before the curve; release sign at the curve exit; end markers
control any policy through step; replaceable detector callback; per-instance VisionMemory and Executor
physics vehicle energy ledger, regeneration ceiling, actual accelerations and jerk under the archived plant
diagnostics per-substep execution record (command, applied acceleration, interval, fallback reason, target distances, speed limit), memory snapshot, memory update diagnostic
restoration complete episode snapshot (vehicle, memory, camera and RNG state, frame history, command boundary, detector state) with configuration-identity checks
interface Gymnasium reset/step; terminated = task outcome, truncated = external cap only

Install

python -m pip install evcrl-0.0.1-py3-none-any.whl      # or: python -m pip install .
evcrl-smoke --mode camera --oracle --episode             # finite API smoke, not an evaluation
python -m pip install 'evcrl[test]' && python -m pytest tests -q

Optional extras: analysis (SciPy, Matplotlib for the companion scripts), torch (only needed by an external learned detector or a training framework; nothing in this package imports it), test.

Quick start

import gymnasium as gym, numpy as np, evcrl

env = gym.make("EvcRL-Camera-v0", profile="paper_v25", detector=evcrl.OracleDetector(seed=0))
obs, info = env.reset(seed=0, options={"signal_offset": 40.0})
obs, reward, terminated, truncated, info = env.step(np.array([0.3], np.float32))
print(info["command_a"], info["applied_a"], info["termination_reason"])
state = env.unwrapped.get_state();  env.unwrapped.set_state(state)

obs is a dict with rgb (uint8 96×160×3) and ego (speed, acceleration, SOC, temperature, elapsed time, remaining task time). The structured environments return the archived 13-dimensional observation (speed, acceleration, remaining distance, profile limit, curve preview, signal distance/phase/time-to-change within 1000 m, SOC, temperature, clock).

Action semantics

step receives one normalized command u ∈ [-1, 1] (shape (1,); a scalar is accepted; values outside the box are clipped and flagged in info["command_clipped"], or rejected with clip_actions=False). The raw acceleration command is 2.6·u for u > 0 and 3.5·u otherwise (evcrl.normalized_to_command), and it is held for four 0.5 s substeps. In every substep the executor decides the acceleration actually applied. The execution record is returned, not summarised:

  • info["applied_a"] — the four applied accelerations;
  • info["substeps"] — per substep: command_u, command_a, applied_a, v0, v1, odom_ds, jerk, jerk_exceeded, fallback, reason, envelope_braking, signal_reason, interval, v_limit, target_distances, reward, reward_components.

The command is the environment action. The package does not offer any applied acceleration (first substep or otherwise) as a learning label; a learner that needs the executed acceleration reads the record. evcrl.command_to_normalized is the inverse mapping for adapters.

Termination and truncation

  • terminated with info["termination_reason"] in settled (arrived and at rest), red_crossing, task_deadline, overshoot (camera task, > 100 m past the destination).
  • The intrinsic deadline (task_deadline_s="historical": 600 s for 4 km, 1312.5 s for 20 km) is a task outcome and carries the archived terminal cost-to-go; task_deadline_s=None removes it (the clock observation channel is then zero).
  • truncated only through max_episode_seconds; it carries no terminal cost. Without either limit an episode is unbounded — wrap with gymnasium.wrappers.TimeLimit if a policy can stall.
  • Stepping an ended environment raises RuntimeError.

Perception

Without a detector the camera environment is blind: the executor has no road-event targets and the archived judge scores the outcome (red crossings, curve overspeed, arrival). Attach a detector with detector=callable:

def detector(rgb: np.ndarray) -> tuple[dict, np.ndarray | None]:
    # dets: {"traffic_light" | "curve_sign" | "end_marker" | "release_sign": {"score": float, "dist_m": float}}
    # color_probs: five probabilities red/yellow/green/off/unknown, or None when no signal is seen

Outputs are validated (unknown classes, non-finite values or a malformed probability vector raise ValueError). Optional hooks: reset(), and get_state()/set_state() (required for snapshots). The callback receives only the RGB frame; renderer labels and truth are never passed to it.

evcrl.OracleDetector is a truth-based detector (detector.requires_truth = True; the environment then passes the renderer's truth distances). It reproduces the archived oracle probe and exists for tests, executor studies and debugging; info["detector_kind"] == "oracle" marks such runs, which must not be reported as camera results. The manuscript's learned detector, its weights and the training framework live in the research repository; wrap them in the callback above.

env.unwrapped.memory_observation(extended=False) returns the legacy 13-dim memory-generated observation and the 6 (or 10) extra memory entries for frozen-policy adapters.

Profiles and identities

profile status rule difference
paper_v25 frozen archived TIV v25 rules: memory propagates event distances by v·dt; no range guard at the 15 m distance freeze
odometry_v26 corrected memory propagates by the physical displacement of the substep
guard_v26 experimental odometry propagation plus a prospective inward-crossing guard at the freeze threshold

evcrl.PROFILES lists every rule parameter explicitly (memory thresholds and margins, executor jerk family, comfort envelope, initial state, settle thresholds, route budgets and deadlines). evcrl.profile_identity(name) hashes that frozen dictionary with evcrl.CONTRACT_VERSION; it is pinned in tests/expected_identities.json, so a change of any rule or of the interface contract fails the test suite instead of silently altering old experiments after a pip upgrade. evcrl.source_identity() hashes the installed rule-implementing modules. Both are reported in info and stored in snapshots; set_state refuses a snapshot whose configuration identity differs and, by default, one taken with different sources.

paper_v25 was checked against the archived research code: with the same commands, camera seed and oracle detection stream, position, speed, applied acceleration, reward, energy ledger, memory snapshots and rendered frames are bit-identical over complete 4 km episodes, and the structured 4 km and 20 km backends are bit-identical to the archived env20 (see SOFTWARE_VERIFICATION.json).

Supported release-bound jerk limits are 2, 3 and 4 m/s³ at the 0.5 s physical step (jerk=). Route geometry, profile and executor parameters are per instance; importing the package or creating environments modifies no module-level configuration and reads no environment variables, so several differently configured environments coexist in one process.

Reset options

options accepts soc (0.85), temperature (288.15 K), speed (16 m/s), signal_offset or signal_offsets (seconds; by default sampled per episode from the seeded RNG), camera_seed (by default drawn from the seeded RNG). The seed determines signal offsets, camera appearance and sensor noise.

Snapshots

get_state() between public steps returns a deep copy of the vehicle, the memory, the camera (appearance and noise RNG), the environment RNG, the frame history, the command boundary and the detector state. set_state() restores it into an environment with the same configuration identity. Snapshots are environment states, not optimizer or replay checkpoints; restore only trusted local data.

Verification and scope

python -m pytest tests -q covers import hygiene (no Torch, no global mutation), Gymnasium check_env for the registered ids, action parsing and the command mapping, command holding and the execution record, the reward ledger, deadline vs. cap, blind and oracle-driven full episodes, detector validation, seed determinism, instance isolation, snapshot round trips (camera and structured, mid-episode, cross-instance), pickling, pinned identities, the memory guard, odometry propagation, the release-bound executor and the exported route profiles. SOFTWARE_VERIFICATION.json records the checked release including the equivalence runs against the archived code.

This release contains no trained detector, no policy weights, no training framework, no multi-vehicle traffic and no real-road validation. It is the environment, its rules and their identities.

Licence and provenance

Apache License 2.0 (see LICENSE). SOURCE_PROVENANCE.json lists the SHA-256 digests of the archived research sources each module derives from and of the packaged modules. See CHANGELOG.md for the changes from the 0.1.0 draft.

Metadata

Release files for evcrl 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for evcrl 0.0.1
File Size Uploaded
evcrl-0.0.1.tar.gz 71.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for evcrl 0.0.1
File Interpreter ABI Platform
evcrl-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 135.0 kB

Release files / evcrl-0.0.1.tar.gz

Download URL evcrl-0.0.1.tar.gz
Size 71.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9d7367e78fee5cb1bba7d408f31c5f068c62e9b212b92aff0eb9c310e0880c91
BLAKE2b-256 checksum
How to use checksums
301f856107348e69d3864569eebc30309107fe38bb4f5ab672e75717bd7fa9e9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.2

Release files / evcrl-0.0.1-py3-none-any.whl

Download URL evcrl-0.0.1-py3-none-any.whl
Size 63.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9a968aab0e39a80538aa81436189e30fe34f49020476662099588a05e75cef5f
BLAKE2b-256 checksum
How to use checksums
287c4a4b7f41dbd7f70f4ab14bcca2cf61159b6003153ee7f99f3c66c96a3aaf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.2

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page