Chrono 10.0.0 cylindrical-shell axis mismatch fixed, but rolling shell-box contact still unstable

48 views
Skip to first unread message

Kirill Vorotnikov

unread,
Sep 13, 2026, 7:54:59 AMSep 13
to ProjectChrono

Hi Chrono developers,

We are using Chrono 10.0.0, ChSystemNSC with the Bullet collision backend, and while validating a rigid wheel on a flat box we found what appears to be an axis inconsistency in the cylindrical-shell collision path.

ChCollisionShapeCylindricalShell publicly defines the shell axis as local Z, and the internal Bullet shell also appears to use Z. However, cbtCylshellBoxCollisionAlgorithm uses the transformed Y axis (getColumn(1)), and in Chrono 10.0.0 cbtCylindricalShellShape::getHalfLength() also reads Y rather than Z.

We built four isolated Chrono 10.0.0 variants from official commit 9faf13dd8f1128dd75ed233a9627027b0422c3f7, with identical public geometry:

  • S0: stock
  • S1: getHalfLength() Y→Z only
  • S2: shell-box algorithm axis column 1→2 only
  • S3: both changes

For a cylindrical shell with radius 70 mm, width 30 mm, local Z aligned with the physical horizontal wheel axle, on a flat box:

  • S0 zero-tilt longitudinal contact-line offset: RMS 40.41 mm, peak 70 mm
  • S1: no contact
  • S2: 0 / 0 mm
  • S3: 0 / 0 mm

So the axis change clearly fixes the zero-tilt contact geometry.

However, S3 still does not produce robust dynamic wheel contact:

  • loaded contact persistence: 256 / 500 steps
  • rolling contact persistence: 189 / 1000 steps
  • rolling longitudinal lever arm: RMS 0.265 mm, peak 2.936 mm
  • rolling normal moment: RMS 0.036 N·m, peak 1.13 N·m
  • 8 penetrating tilted-floor test states still miss contact
  • wall / edge / corner queries are also not fully reliable

We also noticed that current upstream appears to have changed the half-length accessor to Z, while the custom shell-box algorithm still appears to select Y.

Our questions are:

  1. Is getColumn(1) in cbtCylshellBoxCollisionAlgorithm intentional, or should the algorithm use the shell’s public Z axis?
  2. Is the cylindrical-shell/box custom algorithm intended/recommended for a rigid wheel rolling on a flat box in NSC/Bullet?
  3. Is there another transform/convention we are missing?
  4. If cylindrical shell is not the recommended representation, what collision shape/path would you recommend for a rigid circular wheel where the ground normal should pass through the wheel center on a flat plane?
  5. Would you recommend using a rigid-tire/contact-mesh representation, another Chrono collision backend, or a different approach for this use case?

We have a minimal standalone reproducer and the exact S0/S1/S2/S3 diffs/results and can provide them.

Thanks.


Dan Negrut

unread,
Oct 1, 2026, 2:29:17 PM (3 days ago) Oct 1
to Kirill Vorotnikov, ProjectChrono

Hi Kirill,

 

Apologies that this sat for so long. You are right on both counts, and I have checked it against today's main rather than 10.0.0.

 

The shell's axis is Z throughout the shape: the public header says so, the Bullet shell is built with half extents (radius, radius, half height), its support function reads the half height from Z, and the collision model injects it with no rotation. The shell-box algorithm nevertheless reads the axis from column 1, which is Y, and that is a bug. Your other finding, getHalfLength reading Y, which for this shape returns the radius rather than the half height, was fixed on main on 8 August as a side effect of the rounded-shapes work, which is why upstream now has a correct half length and a wrong axis. Your S1 and S2 results fall out of that exactly: fixing the half length alone narrowed the shell while the axis was still wrong, and fixing the axis alone worked because the wrong half length was the radius, which is larger than the true half width and hid the error.

 

So that this does not fall through the cracks again, I opened an issue with both parts, the axis bug and the question your S3 results raise about whether this algorithm is meant to carry a rolling wheel at all:

 

https://github.com/projectchrono/chrono/issues/848

 

Two requests. Please attach your reproducer and the S0 to S3 diffs there, since they make the case better than anything I can write. And if you are willing, open the pull request for the axis line yourself. You found it and bisected it, and the credit should be yours; your last fix went in the same day.

 

On your practical questions 4 and 5. The S3 numbers, contact present on roughly half the steps on a flat face, are not a tuning problem. The algorithm's own header says it replaces the shell with a capsule per box direction and may produce zero, one or two contacts, so intermittent contact on a plane is built into the method. Whether it should be improved or documented as not for wheels is a call for the maintainers, and the issue asks them. For your rigid wheel today, use what the vehicle code itself uses on Bullet: a ChCollisionShapeCylinder, which goes through Bullet's standard convex machinery and never touches this custom algorithm, or a triangle mesh, which is what ChRigidTire::SetContactMesh does. The cylindrical shell earns its keep in the multicore collision system, where it has its own narrowphase; that is where the demos use it as the default tire shape.

 

Thank you for the careful work, twice now :-)

Dan

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

Robert and Laura Hensel Professor

NVIDIA CUDA Fellow

Department of Mechanical & Aerospace Engineering

Department of Electrical & Computer 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/7fbaeabd-bc22-4497-b51e-f698278014d3n%40googlegroups.com.

Radu Serban

unread,
Oct 3, 2026, 1:22:58 PM (yesterday) Oct 3
to ProjectChrono

Hi Kyrill,

 

Sorry for joining the party so late. I meant to reply to your first query, but I was busy over the last month and only now things are calming down some (I’m still on travel for 10 more days).

 

You and Dan have correctly concluded that there is a bug in the current implementation of the cylindrical shell collision primitive and have a fix (I haven’t looked at that yet, but I assume it’s correct).  Having said that, I’d like to step back a bit, give some context, and then ask one question.

 

I implemented this particular collision shape a while ago when I was looking to reduce the cost of simulating tracked vehicles; I wanted to see if using this simplified cylindrical shape (which ignores the caps) can help with efficiency by allowing a simple analytical collision detection against boxes (the main interaction between track wheels and rollers against track shoes). It turned out that the savings were not really worth it and I abandoned using it in any models and simulations. For reasons I will not get into right now, this code found its way in the main branch.

 

Lately, I have been culling the Chrono code for dead code and features that nobody really uses, and which only add complexity to the code and make maintenance more difficult. The cylindrical shell shape was on the chopping block. But then you posted and I said I will get back to you with this very discussion before making a decision in that regard (as I already mentioned, I got swept with other things and didn’t get a chance to do so).

 

The question I wanted to ask you is simply whether you really need this collision shape. If the answer is no, then my inclination would be to completely retire the shape altogether. If you have a legit application for it, we can keep it and fix it as in your PR.

 

From your message, I gather that you don’t particularly need this shape. Your question was if this is suitable for a rigid wheel on rigid flat terrain.  The answer is *no*.  You are better off using either a cylinder (you will get the exact same behavior for the side walls as with the cylindrical shell and also interaction with the caps). Even better, use a “rounded cylinder” shape; until recently, this shape was not fully implemented in Chrono. At the request of another user, I filled in the missing support for both rounded cylinders and rounded boxes.  By the way, if I recall correctly, that user wanted to use rounded cylinders for the exact same type of application as you (rigid wheel on rigid terrain).

 

So, the bottom line is this: from where I sit, the cylindrical shell shape is not really useful, and I would prefer to obsolete it. If however, you have a good argument for keeping it, we’ll simply adopt the fix in your PR (I’d like to get a chance to look at it more carefully first). Please let me know.

 

Best,
Radu

 

From: projec...@googlegroups.com <projec...@googlegroups.com> On Behalf Of Kirill Vorotnikov
Sent: Sunday, 13 September 2026 14:55
To: ProjectChrono <projec...@googlegroups.com>
Subject: [chrono] Chrono 10.0.0 cylindrical-shell axis mismatch fixed, but rolling shell-box contact still unstable

 

Hi Chrono developers,

--

Kirill Vorotnikov

unread,
Oct 3, 2026, 2:30:56 PM (yesterday) Oct 3
to ProjectChrono

Hi Radu,

Thank you - this context is very helpful!

No, we do not specifically need the cylindrical-shell collision shape. Our actual application is a rigid wheel on rigid terrain, and the shell was only investigated because we were looking for a physically appropriate wheel contact representation.

Given your explanation, I would not argue for keeping the cylindrical shell on our account. If you prefer to retire it, that is perfectly fine from our side.

Dan had suggested either a standard cylinder or a triangle contact mesh for the Bullet path. Based on your recommendation, we will now evaluate the rounded cylinder first, using the standard cylinder as a reference.

Regarding PR #853: I opened it at Dan’s request for the confirmed axis bug. I am happy to leave it open while you decide whether to keep or obsolete the shape, or close it if retiring the shape is the preferred direction.

Thanks again for taking the time to explain the history and intended use of this primitive.

Best regards,
Kirill.

Radu Serban

unread,
Oct 3, 2026, 2:40:07 PM (yesterday) Oct 3
to ProjectChrono

Hi Kirill,

 

I’ll look again into this when I return from travel (mid-October) and decide then. I’ll let you know.

 

A triangle mesh like Dan suggested is a perfectly valid option, but I would use that only if the desired geometry cannot be described with a primitive shape (cylinder, rounded cylinder, etc). If you are interested in a wheel that is a perfect cylinder, model it as a cylinder. If capturing the tread is important, use a triangular mesh.

 

It’d be great if you could report back here what you find when using a rounded cylinder. I didn’t get a chance to experiment with that shape as a wheel model after completing its implementation.

 

--Radu

Kirill Vorotnikov

unread,
Oct 3, 2026, 3:11:41 PM (yesterday) Oct 3
to ProjectChrono

Hi Radu,

I started with the rounded-cylinder option you suggested, but hit a geometry-semantics issue before running any dynamics, so I stopped there rather than guessing parameters.

For our wheel the desired external geometry is 140 mm diameter, 30 mm total width, with approximately a 5 mm edge radius.

From the current public ChCollisionShapeRoundedCylinder geometry contract, this appears to correspond to:

  • radius = 65 mm
  • height = 20 mm
  • sweep radius = 5 mm

That gives the expected public bounding dimensions of 140 mm diameter and 30 mm width.

However, following the current Bullet conversion path on main (9e95a025... in my checkout), the same parameters appear to produce Bullet half-extents corresponding to 130 mm diameter and 20 mm width at zero envelope. Conversely, using radius = 70 mm and height = 30 mm to match the Bullet outer extents makes the public shape bounding box 150 mm × 40 mm once the 5 mm sweep is included.

So before testing contact behavior, I wanted to check the intended parameter convention:

Should radius and height describe the core cylinder, with sphere_swept added outward, or should they describe the final outer cylinder envelope with the sweep contained inside it?

I may simply be reading the new Bullet conversion incorrectly, but the public shape geometry and the Bullet support/AABB path currently appear to use different conventions.

I stopped before dynamics so I wouldn’t tune the wheel geometry around the wrong interpretation.

If useful, I can post the exact source locations and the small geometry check.

Best regards,
Kirill

Radu Serban

unread,
6:59 AM (16 hours ago) 6:59 AM
to ProjectChrono

Hi Kirill,

 

There were indeed some inconsistencies in how rounded cylinders were defined/used in different parts of the code.

I unified them into the following convention: “radius and height specify the overall (outer) size of the object with the “rounding” sradius cut into it”  (that is, your last option below: the parameters define “the final outer cylinder envelope with the sweep contained inside it”). This is also consistent with how other shapes are defined and treated for things like the MPR narrowphase algorithm in the multicore collision detection.
So, for your desired wheel geometry, you should use radius=70, height=30, sradius=5.

 

There were a couple of other things I had left out during my first pass at implementing the rounded cylinder and box shapes (e.g., the volume and gyration calculations were approximated by those of the skeleton shape) which are now fixed.

 

Then, I asked Claude to generate a unit test. See utest_COLL_rounded_shapes.

 

The code is available in the ‘main’ branch. Please let me know if you find any other issues with these two shapes.
--Radu

Kirill Vorotnikov

unread,
1:56 PM (9 hours ago) 1:56 PM
to ProjectChrono

Hi Radu,

Thanks again. I tested the updated rounded-cylinder implementation on current main at commit c6acd4e5a199f56052ba74b8e9d735a2157ba613.

The geometry side now looks good: radius=70 mm, height=30 mm, sradius=5 mm gives the expected 140 mm × 30 mm outer wheel envelope, and both utest_COLL_rounded_shapes and the nearby Bullet utility tests pass.

Before going further with the full robot, I reduced the issue to a very small standalone NSC/Bullet reproducer: one rigid wheel, one flat box, and a minimal support constraint. I also included a standard-cylinder control.

What I see appears not to be RoundedCylinder-specific.

With zero envelope and zero safe margin, both RoundedCylinder and Cylinder show highly intermittent support. With zero envelope and a common 0.1 mm safe margin:

  • RoundedCylinder: mean lateral contact force Fy ≈ -4.25 N
  • Cylinder: mean lateral contact force Fy ≈ -13.37 N

The forces are balanced by the support constraint and the full force-balance residual is below 1e-7 N, so the arithmetic is internally consistent.

For RoundedCylinder with friction set to zero, the mean lateral force drops to about +0.50 N, but support is still intermittent.

I therefore do not think this is evidence of a RoundedCylinder-specific bug. It may instead be that my NSC/Bullet margin/envelope settings or the support fixture are not the right baseline for this kind of small rigid wheel.

I attached a minimal standalone reproducer containing only:

  • README.md
  • CMakeLists.txt
  • reproducer.cpp

Could you please advise what collision envelope, safe margin, and NSC solver settings you would recommend as a baseline for a rigid wheel of about 70 mm radius on rigid flat terrain? I would also appreciate any comments on whether the minimal support fixture in the reproducer is appropriate for this test.

Best regards,
Kirill

chrono_small_wheel_nsc_reproducer.zip
Reply all
Reply to author
Forward
0 new messages