Help with Rolling Friction Behavior in PyChrono SMC Model

81 views
Skip to first unread message

mathias dalby larsen

unread,
Mar 24, 2025, 1:12:21 PM3/24/25
to projec...@googlegroups.com
Hello,
I'm currently working on a PyChrono model using the SMC (Smooth Contact) method to demonstrate how rolling friction behaves in simulations. The setup I'm aiming to replicate is illustrated in the attached diagram, where the goal is to observe different states of motion: stationary, pure rolling, pure sliding, and combined rolling and sliding (as shown in the second image).
However, in my implementation, I am only able to achieve a combination of rolling and sliding, when chaning the friction values. Additionally, even with the wall set at a 0° incline and a friction coefficient of 0.25, the sphere continues to roll indefinitely instead of coming to rest.
Any guidance or insights into what might be wrong with my setup would be greatly appreciated.
PS.From my countless tests, it seems like the material data is only applied during the first contact, however, I'm not quite sure.
Best regards,
Mathias Dalby Larsen

Code used 
import pychrono as chrono
import pychrono.irrlicht as chronoirr
import numpy as np

# Simulation Parameters
sphere_radius = 0.2  # meters
sphere_mass = 5.0  # kg
initial_velocity = 0.0  # m/s (parallel to incline, pointing up)
incline_angle = 5  # degrees (fix the floor at this angle)
static_friction = 0.25  # μs
kinetic_friction = 0.25 # μk
Rolling_friction = 0.50 # Rolling friction coefficient
measure_time = 4.5  # Time after which velocities will be measured
sim_time = 10
wall_depth = 15.0  # From wall dimensions

# Convert incline angle to radians
alpha_rad = np.radians(incline_angle)

# Create system
sys = chrono.ChSystemSMC()

# Check the current normal contact force model
print("Normal contact force before setting:", sys.GetContactForceModel())  # Should return default value

# Try setting it to Hooke
#sys.SetContactForceModel(chrono.ChSystemSMC.Hooke)  # Set Hooke model explicitly
# Try setting it to Hertz
sys.SetContactForceModel(chrono.ChSystemSMC.Hertz)  # Set Hertz model explicitly
# Try setting it to PlainCoulomb
#sys.SetContactForceModel(chrono.ChSystemSMC.PlainCoulomb)  # Set PlainCoulomb model explicitly
# Try setting it to Flores
#sys.SetContactForceModel(chrono.ChSystemSMC.Flores)  # Set Flores model explicitly

# Check if it changed
print("Normal contact force after setting:", sys.GetContactForceModel())  # Should print 1 (Hertz)

# Check the current tangential contact force model
print("Tangential contact force before setting:", sys.GetTangentialDisplacementModel())  # Should return default value

# Try setting it to None
#sys.SetTangentialDisplacementModel(chrono.ChSystemSMC._None)  # Set None model explicitly
# Try setting it to OneStep
#sys.SetTangentialDisplacementModel(chrono.ChSystemSMC.OneStep)  # Set OneStep model explicitly
# Try setting it to MultiStep
sys.SetTangentialDisplacementModel(chrono.ChSystemSMC.MultiStep)  # Set MultiStep model explicitly

# Check if it changed
print("Tangential contact force after setting:", sys.GetTangentialDisplacementModel())  # Should print 1 (Hertz)


# Create Collision detection system and solver
sys.SetCollisionSystemType(chrono.ChCollisionSystem.Type_BULLET)
sys.SetSolverType(chrono.ChSolver.Type_BARZILAIBORWEIN)
sys.GetSolver().AsIterative().SetMaxIterations(200)
sys.UseMaterialProperties(True)

# Set gravitational acceleration
sys.SetGravitationalAcceleration(chrono.ChVector3d(0, -9.81, 0))


# Create a material for the inclined wall
wall_mat = chrono.ChContactMaterialSMC()
wall_mat.SetStaticFriction(static_friction)
wall_mat.SetSlidingFriction(kinetic_friction)
wall_mat.SetRollingFriction(Rolling_friction/2)
wall_mat.SetRestitution(0.50)
wall_mat.SetYoungModulus(1e9)
wall_mat.SetPoissonRatio(0.3)
wall_mat.SetSpinningFriction(Rolling_friction * 20.0)
wall_mat.SetKn(1e9)
wall_mat.SetKt(1e9)

# Create the inclined wall (static floor)
wall = chrono.ChBodyAuxRef()
wall.SetFixed(True)
wall.SetInertiaXX(chrono.ChVector3d(0.1, 0.1, 0.1))
wall.EnableCollision(True)

# Apply correct rotation using `QuatFromAngleAxis`
rotation_axis = chrono.ChVector3d(1, 0, 0)  # Rotate around X-axis
wall_rotation = chrono.QuatFromAngleAxis(-alpha_rad, rotation_axis)
wall.SetRot(wall_rotation)

# Position the wall correctly
wall.SetPos(chrono.ChVector3d(0, 0, 0))

# Add collision shape
wall_shape = chrono.ChCollisionShapeBox(wall_mat, 2, 0.1, wall_depth)
wall.AddCollisionShape(wall_shape)

# Add visual representation
wall_vis = chrono.ChVisualShapeBox(2, 0.1, wall_depth)
wall_vis.SetColor(chrono.ChColor(1, 0, 0))  # Red for visibility
wall.AddVisualShape(wall_vis)

# Add to system
sys.Add(wall)

# Create the rolling sphere
sphere = chrono.ChBody()
sphere.SetMass(sphere_mass)
sphere.SetInertiaXX(chrono.ChVector3d(2/5 * sphere_mass * sphere_radius**2,
                                     2/5 * sphere_mass * sphere_radius**2,
                                     2/5 * sphere_mass * sphere_radius**2))

# Function to calculate the circle's center position
def get_circle_position(radius, theta):
    y_c = -(radius+0.05) * np.sin(theta)
    z_c = (radius+0.05) * np.cos(theta)
    return y_c, z_c
# Get the position of the circle center
circle_pos = get_circle_position(sphere_radius, alpha_rad)
sphere.SetPos(chrono.ChVector3d(0, circle_pos[1]+0.01, circle_pos[0]+0.01))


# Set initial velocity along the incline
sphere.SetPosDt(chrono.ChVector3d(0,initial_velocity * np.sin(alpha_rad),
                                 initial_velocity * np.cos(alpha_rad)))

# Add sphere collision and visualization
sphere_mat = chrono.ChContactMaterialSMC()
sphere_mat.SetStaticFriction(static_friction)
sphere_mat.SetSlidingFriction(kinetic_friction)
sphere_mat.SetRollingFriction(Rolling_friction/2)
sphere_mat.SetRestitution(0.50)
sphere_mat.SetYoungModulus(1e9)
sphere_mat.SetPoissonRatio(0.3)
sphere_mat.SetSpinningFriction(Rolling_friction * 20.0)
sphere_mat.SetKn(1e9)
sphere_mat.SetKt(1e9)

# Assign material directly to the body
sphere_shape = chrono.ChCollisionShapeSphere(sphere_mat, sphere_radius)
sphere.AddCollisionShape(sphere_shape)
sphere.EnableCollision(True)

sphere_vis = chrono.ChVisualShapeSphere(sphere_radius)
sphere_vis.SetColor(chrono.ChColor(1, 1, 0))  # Yellow sphere
sphere.AddVisualShape(sphere_vis)

# Add sphere to system
sys.Add(sphere)

# Set up the Irrlicht visualization
vis = chronoirr.ChVisualSystemIrrlicht()
vis.AttachSystem(sys)
vis.SetWindowSize(1024, 768)
vis.SetWindowTitle('Rolling Ball on Inclined Wall')
vis.Initialize()
vis.AddSkyBox()
vis.AddCamera(chrono.ChVector3d(-2, 0, -0.5), chrono.ChVector3d(0, 0, 0))
vis.AddTypicalLights()

# Simulation loop
time = 0.0
dt = 10e-6  # Keep accurate physics time step
render_interval = 1000  # Render every 10th step for 10x faster visual effect
step_count = 0
realtime_timer = chrono.ChRealtimeStepTimer()
lin_vel = None

while vis.Run():
    if step_count % render_interval == 0:  # Render only every 10th step
        vis.BeginScene()
        vis.Render()
        vis.EndScene()
   
    # Advance simulation
    sys.DoStepDynamics(dt)
    time += dt
    step_count += 1

    # Adjust real-time sync for 10x faster visualization
    if step_count % render_interval == 0:
        realtime_timer.Spin(dt * render_interval)

    # Measure velocities at exactly measure_time
    if time >= measure_time and lin_vel is None:  # Only measure once
        lin_vel = sphere.GetLinVel().Length()  
        ang_acc = sphere.GetAngVelLocal().Length()  # Angular acceleration magnitude
        Rollslide = abs((sphere_radius * ang_acc))
        print(f"Measured at {measure_time}s -> Lin Vel: {lin_vel}, Rot Change: {ang_acc}, Rot rollslide: {Rollslide}")
        force = sphere.GetContactForce()
        torque = sphere.GetContactTorque()
        print(f"Time: {time:.3f} - Contact Force: {force.Length()}, Contact Torque: {torque.Length()}")


Dan Negrut

unread,
Mar 25, 2025, 1:21:52 PM3/25/25
to mathias dalby larsen, projec...@googlegroups.com

Mathias – unfortunately, I do not have the time/expertise to take a deep dive in your post. But I’ll offer some quick suggestions, perhaps you’ll find them useful.

 

There are many ways to handle friction and contact in Chrono. Which one you should choose depends on what you want to simulate.

 

If things don’t pan out in PyChorno, you might want to look into the C++ solver, which is an overset of what you find in PyChrono. For all purposes, PyChrono makes library calls into Chrono.

 

Also, a recent frictional contact implementation that you can use is in Chrono DEM: https://github.com/projectchrono/DEM-Engine.

This is what you want to use if you are interested in large numbers of bodies mutually interacting. It has good penalty support for handling friction and contact.

 

Dan

---------------------------------------------

Bernard A. and Frances M. Weideman Professor

NVIDIA CUDA Fellow

Department of Mechanical Engineering

Department of Computer Science

University of Wisconsin - Madison

4150ME, 1513 University Avenue

Madison, WI 53706-1572

608 772 0914

http://sbel.wisc.edu/

http://projectchrono.org/

---------------------------------------------

--
You received this message because you are subscribed to the Google Groups "ProjectChrono" group.
To unsubscribe from this group and stop receiving emails from it, send an email to projectchron...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/projectchrono/SA1P220MB1275A64A7BE884B285864FFDAEA42%40SA1P220MB1275.NAMP220.PROD.OUTLOOK.COM.

Radu Serban

unread,
Mar 26, 2025, 3:09:35 PM3/26/25
to projec...@googlegroups.com

Hi Mathias,

 

The most complete SMC model is implemented in the Chrono::Multicore module.  I never got around to bring up the corresponding SMC model in the core Chrono module to the same level (although that is on one of the many TODO lists I keep).

Compared to the Chrono core implementation (see the implementation in ChContactSMC.h), the SMC contact model in Chrono::Multicore (see ChIterativeSolverMulticoreSMC.cpp) has the following two main additional features:

  • A multi-step tangential displacement model (see this paper for details on why that is important in SMC); and
  • Rolling and spinning friction

 

With the above, the kind of simulations you are interested in will give the expect results. In fact, such behaviors are implemented and tested in a series of tests that are included in the Chrono distribution: see the unit tests for multicore SMC contact.

 

Having said all of that, please note that the Chrono::Multicore module is currently *not* SWIG wrapped and as such not available through PyChrono.

 

Best,
Radu

 

 

From: projec...@googlegroups.com <projec...@googlegroups.com> On Behalf Of mathias dalby larsen
Sent: Monday, March 24, 2025 10:12 AM
To: projec...@googlegroups.com
Subject: [chrono] Help with Rolling Friction Behavior in PyChrono SMC Model

 

Hello,

--

mathias dalby larsen

unread,
Apr 16, 2025, 2:25:13 AM4/16/25
to ProjectChrono
Thank you this was exactly what i needed.

Dan Negrut

unread,
Apr 16, 2025, 8:26:09 AM4/16/25
to mathias dalby larsen, ProjectChrono

Mathias - Here’s another source of information that you might find useful: https://academic.oup.com/mnras/article/498/1/1062/5893804

 

Dan

---------------------------------------------

Bernard A. and Frances M. Weideman Professor

NVIDIA CUDA Fellow

Department of Mechanical Engineering

Department of Computer Science

University of Wisconsin - Madison

4150ME, 1513 University Avenue

Madison, WI 53706-1572

608 772 0914

http://sbel.wisc.edu/

http://projectchrono.org/

---------------------------------------------

 

Reply all
Reply to author
Forward
0 new messages