| name | body_creation |
| description | Create rigid bodies with mass, geometry, collision shapes, and visual assets. |
| compatibility | pychrono >= 8.0 |
| metadata | {"domain":"mbs"} |
Skill: MBS Body Creation
Purpose
Create rigid bodies — using easy factory functions or manually — with mass, geometry, collision shapes, and visual assets.
When to Use
When populating a simulation with floors, objects, cranks, pistons, pendulum arms, or any physical part.
PyChrono Defaults — Know Before Customizing
| Shape / Factory | Cylinder axis (body-local) | Visual auto-added? |
|---|
ChVisualShapeCylinder (manual) | Z | No — must call AddVisualShape explicitly |
ChBodyEasyCylinder(ChAxis_Y, ...) | Y | Yes — do NOT call AddVisualShape again |
ChBodyEasyCylinder(ChAxis_X, ...) | X | Yes — do NOT call AddVisualShape again |
ChBodyEasyCylinder(ChAxis_Z, ...) | Z | Yes — do NOT call AddVisualShape again |
Rule: Easy factory bodies already have a visual shape built in. Never call AddVisualShape
on an easy factory body for the same shape — that creates a duplicate visual.
Easy Factory vs Manual — Choose Before Writing Code
Use ChBodyEasyBox / ChBodyEasySphere freely for any body shape.
Use ChBodyEasyCylinder only when:
- The body is a fixed or structural element (post, column, ground pin) whose axis-aligned
orientation (ChAxis_X/Y/Z) directly matches the world orientation without further
SetRot
- OR the simulation doesn't require re-orienting the body during the run
Use ChBody + ChVisualShapeCylinder for:
- Any link body whose orientation is non-trivial or changes during simulation
(crank, connecting rod, pendulum arm, any rotating or translating link)
- Reason: manual setup gives full control; the two-step visual formula below applies only
to manual
ChBody + ChVisualShapeCylinder — not to easy factory bodies
Easy Factory Bodies (simplest approach)
These create the ChBody, add a visual shape, optionally add a collision shape, and set the mass from density — all in one call.
box_sx = float
box_sy = float
box_sz = float
box_density = float
body = chrono.ChBodyEasyBox(box_sx, box_sy, box_sz, box_density, True, True, mat)
cyl_radius = float
cyl_height = float
cyl_density = float
body = chrono.ChBodyEasyCylinder(chrono.ChAxis_Y, cyl_radius, cyl_height, cyl_density, True, True, mat)
sph_radius = float
sph_density = float
body = chrono.ChBodyEasySphere(sph_radius, sph_density, True, True, mat)
After factory creation:
body.SetPos(chrono.ChVector3d(x, y, z))
body.SetFixed(True)
sys.Add(body)
Manual Body Setup (full control)
Use this path for any link body (crank, rod, pendulum arm, etc.):
mass = float
inertia_xx = float
pos_x = float
pos_y = float
pos_z = float
body = chrono.ChBody()
body.SetMass(mass)
body.SetInertiaXX(chrono.ChVector3d(inertia_xx, inertia_xx, inertia_xx))
body.SetPos(chrono.ChVector3d(pos_x, pos_y, pos_z))
body.EnableCollision(False)
sys.AddBody(body)
Cylinder Orientation — General Rule (manual ChBody only)
Goal: make the cylinder visual point along the link's physical axis in the world.
Convention: define body-local X as the link direction. Then apply two steps:
Step 1 — Body rotation:
body.SetRot(rotation_that_points_body_local_X_along_link_direction)
→ encodes the link direction in world space
Step 2 — Visual offset (always the same formula):
cyl = chrono.ChVisualShapeCylinder(radius, height)
body.AddVisualShape(cyl, chrono.ChFramed(chrono.VNULL, chrono.QuatFromAngleY(chrono.CH_PI_2)))
→ rotates cylinder axis from body-local Z to body-local X
Why it works:
ChVisualShapeCylinder default axis is body-local Z
QuatFromAngleY(CH_PI_2) rotates Z → X
- So the cylinder ends up pointing along body-local X, which Step 1 aligned with the link
ChFramed position = VNULL when body.SetPos() is at the link's midpoint (body COM)
Never invent per-body magic ChFramed rotations. Use SetRot to encode orientation,
and always use the same ChFramed(VNULL, QuatFromAngleY(CH_PI_2)) offset for the visual.
Step 1 Rotation by Case
body.SetRot(chrono.QuatFromAngleZ(theta))
body.SetRot(chrono.QUNIT)
body.SetRot(chrono.QuatFromAngleAxis(angle, axis_vector))
Rotation helpers (quaternion constants and functions)
chrono.QUNIT
chrono.QuatFromAngleZ(angle_rad)
chrono.QuatFromAngleY(angle_rad)
chrono.QuatFromAngleX(angle_rad)
chrono.QuatFromAngleAxis(angle_rad, chrono.VECT_X)
chrono.Q_ROTATE_Y_TO_Z
chrono.Q_ROTATE_Y_TO_X
chrono.Q_ROTATE_Z_TO_X
Visual Shapes (attach to manual ChBody)
vs_sx = float
vs_sy = float
vs_sz = float
box_shape = chrono.ChVisualShapeBox(vs_sx, vs_sy, vs_sz)
box_shape.SetTexture(chrono.GetChronoDataFile('textures/concrete.jpg'))
body.AddVisualShape(box_shape)
vs_radius = float
sph_shape = chrono.ChVisualShapeSphere(vs_radius)
body.AddVisualShape(sph_shape, chrono.ChFramed(chrono.ChVector3d(offset_x, 0, 0)))
cyl_shape = chrono.ChVisualShapeCylinder(radius, height)
body.AddVisualShape(cyl_shape, chrono.ChFramed(chrono.VNULL, chrono.QuatFromAngleY(chrono.CH_PI_2)))
Texture / Visual Material
body.GetVisualShape(0).SetTexture(chrono.GetChronoDataFile("textures/bluewhite.png"))
vis_mat = chrono.ChVisualMaterial()
vis_mat.SetKdTexture(chrono.GetChronoDataFile("textures/concrete.jpg"))
body.GetVisualShape(0).SetMaterial(0, vis_mat)