一键导入
wheeled-vehicle
Create and configure wheeled vehicles (HMMWV, CityBus, FEDA, custom JSON) with engine, transmission, drive, steering, and tire settings.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Create and configure wheeled vehicles (HMMWV, CityBus, FEDA, custom JSON) with engine, transmission, drive, steering, and tire settings.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | wheeled_vehicle |
| description | Create and configure wheeled vehicles (HMMWV, CityBus, FEDA, custom JSON) with engine, transmission, drive, steering, and tire settings. |
| compatibility | pychrono >= 8.0 |
| metadata | {"domain":"veh"} |
Create PyChrono wheeled vehicles without losing system ownership, vehicle subsystem updates, FSI coupling, or vehicle-specific VSG rendering.
Use this skill when a scene contains HMMWV, CityBus, FEDA, Polaris, or any
veh.WheeledVehicle JSON vehicle.
HMMWV_Full, CityBus, FEDA):
create the wrapper with no args, initialize it, then get system from the
wrapper.HMMWV_Reduced:
veh.HMMWV_Reduced(sys) is the only wrapper variant that takes a system.veh.WheeledVehicle(sysMBS, json_path).veh.WheeledVehicle(json_path, chrono.ChContactMethod_SMC).ChSystem to HMMWV_Full, CityBus, or FEDA.
These wrappers create and own their system internally.Initialize() before Set*VisualizationType(...).run_recording_loop, pass a custom
step_fn; the default step only advances the raw ChSystem, not driver,
terrain, tire, and powertrain subsystems.sysMBS as the
first constructor argument. Do not "fix" overload errors by dropping sysMBS.vehicle.GetSystem() is sysMBS in Python. Some PyChrono
builds return a different wrapper/base pointer even when the 2-arg shared
system constructor is correct. Verify by behavior/body registration instead.ChDataDriver; do not use
ChInteractiveDriver in batch/headless runs.build_fsi_vehicle_visualizer(...). Do not also create a generic
chronovsg.ChVisualSystemVSG().hmmwv = veh.HMMWV_Full()
hmmwv.SetContactMethod(chrono.ChContactMethod_SMC)
hmmwv.SetChassisCollisionType(veh.CollisionType_NONE)
hmmwv.SetChassisFixed(False)
hmmwv.SetInitPosition(chrono.ChCoordsysd(init_loc, init_rot))
hmmwv.SetEngineType(veh.EngineModelType_SHAFTS)
hmmwv.SetTransmissionType(veh.TransmissionModelType_AUTOMATIC_SHAFTS)
hmmwv.SetDriveType(veh.DrivelineTypeWV_AWD)
hmmwv.SetSteeringType(veh.SteeringTypeWV_PITMAN_ARM)
hmmwv.SetTireType(veh.TireModelType_TMEASY)
hmmwv.SetTireStepSize(step_size)
hmmwv.Initialize()
system = hmmwv.GetSystem()
bus = veh.CityBus()
bus.SetContactMethod(chrono.ChContactMethod_SMC)
bus.SetChassisCollisionType(veh.CollisionType_NONE)
bus.SetChassisFixed(False)
bus.SetInitPosition(chrono.ChCoordsysd(init_loc, init_rot))
bus.SetTireType(veh.TireModelType_TMEASY)
bus.SetTireStepSize(step_size)
bus.Initialize()
system = bus.GetSystem()
feda = veh.FEDA()
feda.SetContactMethod(chrono.ChContactMethod_SMC)
feda.SetChassisCollisionType(veh.CollisionType_NONE)
feda.SetChassisFixed(False)
feda.SetInitPosition(chrono.ChCoordsysd(init_loc, init_rot))
feda.SetEngineType(veh.EngineModelType_SIMPLE_MAP)
feda.SetTransmissionType(veh.TransmissionModelType_AUTOMATIC_SIMPLE_MAP)
feda.SetTireType(veh.TireModelType_PAC02)
feda.SetTireStepSize(step_size)
feda.Initialize()
system = feda.GetSystem()
hmmwv = veh.HMMWV_Reduced(sys)
hmmwv.SetInitPosition(chrono.ChCoordsysd(init_loc, init_rot))
hmmwv.SetEngineType(veh.EngineModelType_SIMPLE)
hmmwv.SetTransmissionType(veh.TransmissionModelType_AUTOMATIC_SIMPLE_MAP)
hmmwv.SetDriveType(veh.DrivelineTypeWV_RWD)
hmmwv.SetTireType(veh.TireModelType_RIGID)
hmmwv.Initialize()
For JSON vehicles such as Polaris/Polaris.json, do not call wrapper-only
methods such as SetEngineType, SetTransmissionType, or SetTireType.
Construct veh.WheeledVehicle, then explicitly read and initialize
powertrain and tire JSON files.
# Standalone: vehicle owns a new system. Use only when the vehicle is the
# whole scene.
vehicle = veh.WheeledVehicle(
veh.GetVehicleDataFile("Polaris/Polaris.json"),
chrono.ChContactMethod_SMC,
)
# Shared system: required for FSI scenes and scenes with pre-existing sysMBS
# bodies such as tanks, platforms, floating plates, ramps, or props.
vehicle = veh.WheeledVehicle(
sysMBS,
veh.GetVehicleDataFile("Polaris/Polaris.json"),
)
Valid overloads:
WheeledVehicle(str)WheeledVehicle(str, ChContactMethod[, bool, bool])WheeledVehicle(ChSystem*, str[, bool, bool])There is no WheeledVehicle(ChSystem*, str, ChContactMethod) overload. If
SWIG rejects that call, drop the contact-method argument, not sysMBS.
vehicle = veh.WheeledVehicle(
sysMBS,
veh.GetVehicleDataFile("Polaris/Polaris.json"),
)
vehicle.Initialize(chrono.ChCoordsysd(init_pos, chrono.QUNIT))
engine = veh.ReadEngineJSON(
veh.GetVehicleDataFile("Polaris/Polaris_EngineSimpleMap.json")
)
transmission = veh.ReadTransmissionJSON(
veh.GetVehicleDataFile("Polaris/Polaris_AutomaticTransmissionSimpleMap.json")
)
powertrain = veh.ChPowertrainAssembly(engine, transmission)
vehicle.InitializePowertrain(powertrain)
tire_json = "Polaris/Polaris_RigidTire.json" # FSI/liquid scenes
for axle in vehicle.GetAxles():
for wheel in axle.GetWheels():
tire = veh.ReadTireJSON(veh.GetVehicleDataFile(tire_json))
vehicle.InitializeTire(tire, wheel, chrono.VisualizationType_MESH)
Polaris files normally used here:
Polaris/Polaris.jsonPolaris/Polaris_EngineSimpleMap.jsonPolaris/Polaris_AutomaticTransmissionSimpleMap.jsonPolaris/Polaris_RigidTire.jsonPolaris/Polaris_RigidMeshTire.jsonPolaris/Polaris_TMeasyTire.jsonPolaris/Polaris_Pac02Tire.jsonDo not invent Polaris_Engine.json.
vehicle.Initialize(ChCoordsysd(init_pos, q)) takes the chassis-frame
origin in world coordinates. To rest wheel bottoms on a flat support:
chassis_init_z = support_top_z + tire_radius - front_spindle_z
tire_radius and front_spindle_z are vehicle-specific; read them
from the shipped JSONs via the project helper rather than hardcoding:
from chrono_code.utils.vehicle_geometry import chassis_init_z
init_z = chassis_init_z(vehicle_json, support_top_z, tire_json=<tire you load>)
init_pos = chrono.ChVector3d(planner_x, planner_y, init_z)
X/Y come from the planner's scene_predicates[]; only Z is derived
here, because the planner doesn't know per-vehicle suspension geometry.
The chassis-frame origin is not the geometric center for every
vehicle. Polaris puts the front axle at x=0 and the rear axle at
x=-2.7153 in chassis frame, so calling
polaris.Initialize(ChCoordsysd(ChVector3d(-4, 0, z))) lands the front
axle at world x=-4 and the rear axle at x=-6.72 — 0.72 m past the
left edge of a [-6, -2] platform. HMMWV / Sedan put the chassis origin
at the geometric center, so the same shift convention does not generalize.
Codegen cannot guess which convention applies without reading the JSON,
so the contract is: every wheeled-vehicle simulation.py MUST assert
the world-frame footprint immediately after Initialize(...).
from chrono_code.utils.vehicle_geometry import assert_vehicle_on_support
polaris.Initialize(chrono.ChCoordsysd(init_pos, chrono.QUNIT))
assert_vehicle_on_support(
polaris,
VEHICLE_JSON, # same path passed to chassis_init_z
support_x_range=(LEFT_PLT_X - PLT_X / 2, LEFT_PLT_X + PLT_X / 2),
support_y_range=(LEFT_PLT_Y - PLT_Y / 2, LEFT_PLT_Y + PLT_Y / 2),
support_top_z=PLT_TOP_Z,
tire_json=TIRE_JSON, # same tire passed to chassis_init_z
support_name="left_platform",
)
The helper reads the four axle spindle positions from the vehicle JSON
(via the same paths chassis_init_z already uses), transforms the
wheel envelopes through the chassis world pose, and checks four edge
clearances + the wheel-bottom z. It does NOT use body.GetTotalAABB()
— that returns ±DBL_MAX for any body without a registered collision
shape, which is the default state of the chassis and spindles
immediately after Initialize(...). Failure messages include the
suggested shift in meters so the next codegen iteration can move
VEH_INIT_X directly instead of guessing.
If the support is the SCM terrain or RigidTerrain (no flat-platform
bounds), pass support_x_range=(-1e9, 1e9) and support_y_range=(-1e9, 1e9) —
the helper still validates the wheel-bottom z, which is the part that
generalizes. Skip the assert entirely only for vehicle-only test rigs
that have no support geometry.
| Context | Tire choice |
|---|---|
| RigidTerrain road | RIGID or TMEASY |
| SCM deformable terrain | TMEASY, PAC02, or FIALA; also call SetTireStepSize(step_size) |
| CRM/granular terrain | TMEASY or PAC02 |
| FSI liquid/floating-body scenes | JSON Polaris_RigidTire.json or Polaris_RigidMeshTire.json |
Do not use wrapper default rigid tires on SCM if the vehicle must actually
drive; wheels spin with little chassis translation. For SCM with non-rigid
tire force models, see veh/terrain for explicit spindle/tire collision
cylinders.
Wrapper visualization type calls go after Initialize():
veh_obj.Initialize()
veh_obj.SetChassisVisualizationType(chrono.VisualizationType_MESH)
veh_obj.SetSuspensionVisualizationType(chrono.VisualizationType_PRIMITIVES)
veh_obj.SetSteeringVisualizationType(chrono.VisualizationType_PRIMITIVES)
veh_obj.SetWheelVisualizationType(chrono.VisualizationType_MESH)
veh_obj.SetTireVisualizationType(chrono.VisualizationType_MESH)
For normal vehicle scenes, use veh.ChWheeledVehicleVisualSystemVSG, not
generic chronovsg.ChVisualSystemVSG.
vis = veh.ChWheeledVehicleVisualSystemVSG()
vis.SetWindowTitle("Vehicle Scene")
vis.SetWindowSize(1280, 1024)
vis.EnableSkyTexture()
vis.SetLightIntensity(1.0)
vis.SetLightDirection(2.0, 0.75)
vis.EnableShadows()
vis.SetChaseCamera(chrono.ChVector3d(0, 0, 1.75), 9.0, 0.5)
vis.AttachVehicle(hmmwv.GetVehicle())
vis.AttachTerrain(terrain)
vis.AttachDriver(driver)
vis.Initialize()
Do not pass an empty sky texture path to SetSkyDomeTexture; it can throw
vsg::Exception in Initialize().
Wrapper vehicle scenes need the full vehicle subsystem loop:
driver_inputs = driver.GetInputs()
driver.Synchronize(time)
terrain.Synchronize(time)
hmmwv.Synchronize(time, driver_inputs, terrain)
vis.Synchronize(time, driver_inputs)
driver.Advance(step_size)
terrain.Advance(step_size)
hmmwv.Advance(step_size)
vis.Advance(step_size)
With run_recording_loop, put that block in step_fn=.... Do not also call
system.DoStepDynamics(step_size) when hmmwv.Advance(step_size) is already
advancing the wrapper-owned system.
When a vehicle interacts with SPH fluid or a floating FSI bridge, each wheel spindle must be registered as an FSI body. Use the shared-system constructor, initialize powertrain/tires, then attach tire collision mesh and FSI geometry to every spindle.
Use the resolved planner scene_predicates[].position for the vehicle spawn.
Do not copy tutorial constants such as -bxDim / 2 - bxDim * CH_1_3 unless
the scene uses exactly that tutorial tank/platform geometry. After initialize,
log the chassis AABB and check the vehicle footprint is supported by the
platform/ramp/bridge.
mesh_filename = veh.GetVehicleDataFile("Polaris/meshes/Polaris_tire_collision.obj")
cmaterial = chrono.ChContactMaterialSMC()
cmaterial.SetYoungModulus(1e8)
cmaterial.SetFriction(0.9)
cmaterial.SetRestitution(0.4)
# Build trimesh / collision shape / ChBodyGeometry FRESH per spindle.
# DO NOT hoist any of these three out of the loop and share across wheels.
# `spindle.AddCollisionShape(shape)` registers the C++ shape's owning-body
# pointer; the second `AddCollisionShape` on the SAME shape object overwrites
# the first owner and the contact handler dereferences a stale pointer at
# the first DoStepDynamics call → SIGSEGV in ChContactContainerSMC::AddContact.
# Same hazard for `ChBodyGeometry`: AddFsiBody stores a pointer into it.
for axle in vehicle.GetAxles():
for wheel in axle.GetWheels():
spindle = wheel.GetSpindle()
trimesh = chrono.ChTriangleMeshConnected()
trimesh = trimesh.CreateFromWavefrontFile(mesh_filename, False, True)
trimesh.RepairDuplicateVertices(1e-9)
wheel_shape = chrono.ChCollisionShapeTriangleMesh(
cmaterial, trimesh, False, False, 0.005
)
spindle.AddCollisionShape(wheel_shape)
spindle.EnableCollision(True)
geometry = chrono.ChBodyGeometry()
geometry.coll_meshes.append(
chrono.TrimeshShape(chrono.VNULL, chrono.QUNIT, mesh_filename, chrono.VNULL)
)
sysFSI.AddFsiBody(spindle, geometry, False)
Do not use sysSPH.CreatePointsBoxInterior(...) for wheel spindles. Box BCE
is for non-rotating blocks/plates, not rotating wheels. The spindle needs all
three calls: AddCollisionShape, EnableCollision(True), and AddFsiBody.
The ChCollisionShapeTriangleMesh + ChBodyGeometry you attach to the
spindle above are collision/BCE coupling geometry. They participate in
contact + fluid pressure transfer. They are NOT the visible tire mesh.
Visual tires come from a separate channel — the vehicle's own tire JSON
loaded by InitializeTire(...):
# Visual tires — driven by the vehicle's own tire mesh assets.
for axle in vehicle.GetAxles():
for wheel in axle.GetWheels():
tire = veh.ReadTireJSON(veh.GetVehicleDataFile(tire_json))
vehicle.InitializeTire(tire, wheel, chrono.VisualizationType_MESH)
# Plus the vehicle-aware visualizer that renders chassis + tires together:
vehicle.SetWheelVisualizationType(chrono.VisualizationType_MESH)
vehicle.SetTireVisualizationType(chrono.VisualizationType_MESH)
Common confusion to avoid:
wheel_shape as the visible tire — it is a
collision proxy used by chrono's contact solver and FSI marker
generator. Hiding/showing it does not change what the user sees.InitializeTire(..., VisualizationType_MESH) because
"spindles already have a mesh attached" — that mesh is the collision
proxy, not the tire visualization. Without InitializeTire(...) the
vehicle visualizer renders bare spindles and the user sees no tires.The two channels are independent:
Always wire BOTH for FSI vehicle scenes.
| Body kind | Pattern |
|---|---|
| Container/tank walls | Use chrono_code.utils.fsi_assets.build_fsi_tank; do not hand-roll wall BCE. |
| Floating non-rotating plate/block | sysSPH.CreatePointsBoxInterior(size) plus sysFSI.AddFsiBody(body, bce, ChFramed(), False). |
| Vehicle wheel spindle | Trimesh ChBodyGeometry plus spindle collision shape; see required pattern above. |
FSI scenes advance with sysFSI.DoStepDynamics(dT). Use two-argument vehicle
synchronization and do not separately step vehicle.Advance, sysMBS, or a
terrain object:
vehicle.Synchronize(sim_time, driver_inputs)
if vis:
vis.Synchronize(sim_time, driver_inputs)
sysFSI.DoStepDynamics(dT)
if vis:
vis.Advance(dT)
For FSI batch/headless runs, use direct veh.DriverInputs() or
veh.ChDataDriver. Do not use ChInteractiveDriver.
driver_inputs = veh.DriverInputs()
if sim_time < 0.4:
driver_inputs.m_throttle = 0.0
driver_inputs.m_braking = 1.0
else:
driver_inputs.m_throttle = 0.45
driver_inputs.m_braking = 0.0
driver_inputs.m_steering = 0.0
Prefer the helper from chrono_code.utils.fsi_assets; it wires the vehicle,
shared MBS system, and SPH plugin into one vehicle-aware VSG visualizer.
from chrono_code.utils.fsi_assets import build_fsi_vehicle_visualizer
visFSI = fsi.ChSphVisualizationVSG(sysFSI)
visFSI.SetSPHColorCallback(fsi.ParticleVelocityColorCallback(0, 5.0))
vis = build_fsi_vehicle_visualizer(
sysMBS,
sysSPH,
sysFSI,
vehicle=vehicle,
sph_visualization=visFSI,
window_title="Vehicle on FSI",
)
Do not create a second generic chronovsg.ChVisualSystemVSG() in the same FSI
vehicle scene.
For wrapper chassis collision against scene props, prefer
chrono_code.utils.add_collision_via_subbodies with CollisionType_NONE.
Do not combine wrapper CollisionType_MESH/PRIMITIVES with sub-body weld
collision. After post-initialize collision shape edits, call
system.GetCollisionSystem().BindAll() once.
For reviewed vehicle scenes, write joint connectivity so overlap validators do not treat suspension and wheel joints as interpenetration bugs:
from chrono_code.utils.scene_assets import write_links_csv
write_links_csv(system, output_dir=str(out_dir))
veh/terrain for terrain creation and SCM tire collision cylinders.veh/driver for driver classes and schedules.fsi/sph for FSI system setup and complete SPH examples.vsg and core/mbs_in_scene for non-FSI visualization/recording.Allowed constructors:
veh.HMMWV_Full()veh.CityBus()veh.FEDA()veh.HMMWV_Reduced(sys)veh.WheeledVehicle(json_path, chrono.ChContactMethod_SMC) for standaloneveh.WheeledVehicle(sysMBS, json_path) for shared-system/FSIForbidden constructs:
veh.HMMWV_Full(sys)veh.CityBus(sys)veh.FEDA(sys)veh.WheeledVehicle(sysMBS, json_path, chrono.ChContactMethod_SMC)assert vehicle.GetSystem() is sysMBSchronovsg.ChVisualSystemVSG() alongside an FSI vehicle visualizerCommon constants and methods:
chrono.ChContactMethod_SMCchrono.VisualizationType_MESHchrono.VisualizationType_PRIMITIVESveh.EngineModelType_SHAFTSveh.EngineModelType_SIMPLEveh.EngineModelType_SIMPLE_MAPveh.TransmissionModelType_AUTOMATIC_SHAFTSveh.TransmissionModelType_AUTOMATIC_SIMPLE_MAPveh.DrivelineTypeWV_FWDveh.DrivelineTypeWV_RWDveh.DrivelineTypeWV_AWDveh.SteeringTypeWV_PITMAN_ARMveh.TireModelType_RIGIDveh.TireModelType_RIGID_MESHveh.TireModelType_TMEASYveh.TireModelType_PAC02veh.TireModelType_FIALAveh.CollisionType_NONEveh.CollisionType_PRIMITIVESveh.CollisionType_MESHEntry point for FSI-coupled hybrid plans (plan_type=fsi_in_scene) — any scene combining SPH fluid (water tanks, dam-break, wave channels) with multi-body dynamics, optionally with a wheeled vehicle. Pick this over mbs_in_scene whenever the plan involves a fluid domain (scene_objects with domain_type starting "sph_") or an FSI body registration (scene_objects with fsi_registration set). Routes to fsi/sph (always), veh/wheeled_vehicle (when vehicle present), and enforces FSI-specific invariants distinct from generic mbs_in_scene rigid scenes.
Entry point for rigid-body hybrid plans (plan_type=mbs_in_scene) combining a robot or vehicle with scene assets — NO fluid coupling. Routes to the correct domain skills and defines only high-level invariants. Use core/fsi_in_scene instead when the plan involves SPH fluid or FSI body registration.
Entry point for pure multi-body simulation plans (plan_type=mbs). Routes the agent to the correct mechanics, system, and camera skills and defines only high-level invariants.
Entry point for static scene plans (plan_type=scene). Routes the agent to the correct scene, system, and camera skills and defines only high-level invariants.
Set up SPH-based Fluid-Structure Interaction (FSI): create ChFsiFluidSystemSPH and ChFsiSystemSPH, configure fluid and SPH parameters, seed fluid particles with hydrostatic initialization, add container BCE boundary markers, register floating rigid bodies, optionally couple with a wheeled vehicle, and advance with sysFSI.DoStepDynamics(dT).
Translate a `geometry_relations` entry from the plan into correct PyChrono coordinate code. Read this whenever the plan declares a relation_name you have not previously encoded, and especially BEFORE writing SetPos / camera placement for any body that participates in a multi-body geometric constraint. Each subsection below is one canonical pattern named exactly as it appears in `plan.geometry_relations[i].relation_name`.