| name | simulation_loop |
| description | Run the time-stepping loop, collect data, and post-process results with matplotlib or CSV. |
| compatibility | pychrono >= 8.0 |
| metadata | {"domain":"mbs"} |
Skill: MBS Simulation Loop
Purpose
Run the time-stepping loop, collect data, and post-process results with matplotlib or CSV output.
When to Use
After setting up the system, bodies, joints, and visualization — to advance the simulation in time and optionally record outputs.
Key Concepts
Basic Loop
dt = float
while vis.Run():
vis.BeginScene()
vis.Render()
vis.EndScene()
sys.DoStepDynamics(dt)
Timestep Guidelines
| Scenario | Typical dt |
|---|
| High-precision mechanisms | 1e-3 (1 ms) |
| General MBS | 5e-3 (5 ms) |
| Collision-heavy scenes | 0.02 (20 ms) |
| SMC soft contacts | 1e-4 (0.1 ms) |
Timed Stop
duration = float
if sys.GetChTime() > duration:
vis.GetDevice().closeDevice()
Setting Initial Body State
body.SetPos(chrono.ChVector3d(x, y, z))
body.SetRot(chrono.QuatFromAngleZ(angle))
body.SetPosDt(chrono.ChVector3d(vx, vy, vz))
body.SetLinVel(chrono.ChVector3d(vx, vy, vz))
body.SetAngVelParent(chrono.ChVector3d(wx, wy, wz))
Reading Body State
body.GetPos()
body.GetPosDt()
body.GetLinVel()
body.GetRot()
body.GetAngVelParent()
Reading Motor State
motor.GetMotorAngle()
motor.GetMotorAngleDt()
motor.GetMotorAngleDt2()
motor.GetMotorPos()
motor.GetMotorPosDt()
motor.GetMotorPosDt2()
Reading Spring State
spring.GetLength()
spring.GetVelocity()
spring.GetForce()
Data Logging (for matplotlib)
Initialize lists before the loop, append inside:
dt = float
duration = float
array_time = []
array_angle = []
array_pos = []
array_speed = []
while vis.Run():
array_time.append(sys.GetChTime())
array_angle.append(motor.GetMotorAngle())
array_pos.append(piston.GetPos().x)
array_speed.append(piston.GetPosDt().x)
vis.BeginScene()
vis.Render()
vis.EndScene()
sys.DoStepDynamics(dt)
if sys.GetChTime() > duration:
vis.GetDevice().closeDevice()
Post-Simulation Matplotlib Plots
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(2, sharex=True)
ax1.plot(array_angle, array_pos)
ax1.set(ylabel='position [m]')
ax1.grid()
ax2.plot(array_angle, array_speed, 'r--')
ax2.set(ylabel='speed [m/s]', xlabel='angle [rad]')
ax2.grid()
plt.xticks(np.linspace(0, 2 * np.pi, 5),
['0', r'$\pi/2$', r'$\pi$', r'$3\pi/2$', r'$2\pi$'])
plt.show()
CSV Output
import csv
dt = float
with open('output.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['time', 'pos_x', 'vel_x'])
while vis.Run():
t = sys.GetChTime()
writer.writerow([t, body.GetPos().x, body.GetPosDt().x])
vis.BeginScene()
vis.Render()
vis.EndScene()
sys.DoStepDynamics(dt)
Periodic Console Output
dt = float
frame = 0
while vis.Run():
vis.BeginScene()
vis.Render()
vis.EndScene()
sys.DoStepDynamics(dt)
if frame % 50 == 0:
print(f"t={sys.GetChTime():.4f} L={spring.GetLength():.4f} F={spring.GetForce():.4f}")
frame += 1
Render-only at fixed intervals (SMC pattern)
dt = float
fps = int
out_step = 1.0 / fps
out_time = 0.0
while vis.Run():
sys.DoStepDynamics(dt)
if sys.GetChTime() >= out_time:
vis.BeginScene()
vis.Render()
vis.EndScene()
out_time += out_step