Rigid bodies float apart when joined with ChLinkUniversal joints

86 views
Skip to first unread message

CK Unsworth

unread,
Jun 16, 2020, 6:47:39 PM6/16/20
to ProjectChrono
Hello,

I am building a simulation of a millipede traversing a step using 26 segments (boxes) connected by rods, attached by universal joints (ChLinkUniversal). Each segment is connected to the adjacent box using a unique rod. My goal is to see how the simulated millipede would passively bend over the step. I'm a beginner PyChrono user and only know basic Python programming.

My issue is that when I run the simulation, the rods do not stay fixed to the center of the boxes and all components eventually float/rotate. I've changed the parameters of each component, including their masses, and this helps stabilize them a bit, but still doesn't solve the floating issue. I imagine the components are being influenced by the others in the series, and this effect compounds as the simulation runs longer.

My questions:

1) How do I affix the rods to the centers of the boxes, so the "millipede" remains in tact?
2) How do I prevent rotation of the boxes?
3) Perhaps there a different method I should be using to achieve the desired output?

Segments (boxes) were each built as follows:
m =.1   #mass
l=1     #length
h=1     #height
d=1     #depth
D=1000  #density
            
seg0 = chrono.ChBodyEasyBox(l,h,d,D, True, True)
seg0.SetPos(chrono.ChVectorD(11.5,7,-1))
seg0.SetBodyFixed(False)
seg0.SetMass(m)
my_system.Add(seg0)
my_color = chrono.ChColorAsset(0,31,40)
seg0.AddAsset(my_color)
seg0.SetCollide(True)
seg0.GetMaterialSurfaceNSC().SetFriction(0.4)
seg0.GetCollisionModel().ClearModel()
seg0.GetCollisionModel().AddBox(0.2, 0.1, 0.1, chrono.VNULL, chrono.ChMatrix33D(chrono.QUNIT))
seg0.GetCollisionModel().BuildModel()

Rods:
a = 20         #rod parameter 1
b = .001       #rod parameter 2
c = .05        #rod paremeter 3    .005 is loose and everything flies away, .5 it is so tight everything curls
rm = .01       #rod mass

rod1 = chrono.ChBody()
my_system.AddBody(rod1)
rod1.SetMass(rm) 
rod1.SetInertiaXX(chrono.ChVectorD(a, b, c))

Joints:
x=11.4      #starting x position

link1 = chrono.ChCylinderShape()
link1.GetCylinderGeometry().p1 = chrono.ChVectorD(x,7,-1)
seg_connect1 = chrono.ChLinkUniversal()
seg_connect1.Initialize(seg0, rod1, chrono.ChFrameD(chrono.ChVectorD(x,7,-1)))
my_system.AddLink(seg_connect1)

link1.GetCylinderGeometry().p2 = chrono.ChVectorD(x-1.3,7,-1)
seg_connect2 = chrono.ChLinkUniversal()
seg_connect2.Initialize(rod1, seg1, chrono.ChFrameD(chrono.ChVectorD(x-1.3,7,-1)))
my_system.AddLink(seg_connect2)
rod1.AddAsset(link1)



See photos below of the simulation progression. Thanks in advance for any tips or advice.

Screenshot (582).png

Screenshot (581).png

The screenshots above reflect approximately what I intend to visualize. (They were taken while the simulation was still running, before everything floated apart.)


Screenshot (580).png

Screenshot (583).png

The last two images are what happens when I let the simulation continue.



Simone Benatti

unread,
Jun 17, 2020, 12:20:17 PM6/17/20
to ProjectChrono
Hi,
it seems to me (I might be wrong) that you are not setting the position of the rod body, but just the start and and of its cylinder shape. 
Use ChBodyEasyCylinder to make sure that the rods are placed where they are supposed to be.
ChBodyEasyCylinder will evaluate mass properties for you, but you can always overwrite them if you have a more accurate estimate.
Best,
Simone

CK Unsworth

unread,
Jun 18, 2020, 12:37:39 AM6/18/20
to ProjectChrono
Hi Simone, 

Thanks so much for the feedback. I see what you mean, I will look into that and post an update if that fixes the issue. 

CK

Radu Serban

unread,
Jun 18, 2020, 1:32:31 AM6/18/20
to projec...@googlegroups.com

CK,

In addition to that, you should make sure the universal joints are properly oriented. I assume you want the 2 rotational DOFs to be about axes that are perpendicular to the axis of your millipede.  Keep in mind that for a universal joint these 2 rotational DOFs are about the x and y axes of the *joint* frame.  If you build the millipede along the global x axis as you seem to do, for the particular form of the Initialize function you use for your joints that will probably require including a rotation about the z axis in the ChFrameD passed to Initialize.

A couple of suggestions:

  • look at demo_IRR_ujoint (https://github.com/projectchrono/chrono/blob/develop/src/demos/python/irrlicht/demo_IRR_ujoint.py) for an example of how to properly connect two bodies with a universal joint.  Note that the two connected bodies there are aligned with the global z axis, unlike your case where I believe you intend them aligned along the global x axis; that dictates the proper orientation of the U-joint.
  • start by defining only one "segment" of your millipede (i.e., one box, one rod, and the U-joint between them) and make sure that is working as expected before extending it to its final configuration.
  • once you have the above, re-arrange your code so that you build the millipede in a for loop (you eliminate code duplication and possible copy-and-paste sources of errors).
  • to test that you model the proper kinematics, use the options in the Irrlicht app (hit key 'i') to render the body and/or joint coordinate frames.  Keep in mind that Irrlicht uses left handed frames so what you see is mirrored from the actual Chrono system.

--Radu

--
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 on the web visit https://groups.google.com/d/msgid/projectchrono/c0e055b0-4f09-4c50-9bd1-34d927e43454o%40googlegroups.com.

CK Unsworth

unread,
Jun 19, 2020, 7:23:53 PM6/19/20
to ProjectChrono
Thanks, Radu. I was wondering about the axes. I restarted as you suggested and created a series of segments connected by U-joints in the correct orientation.

CaptureA.PNG


I made a for loop to extend the segments to a series of 10. However, I am running into the issue of connecting all adjacent segments using the loop since it does not assign each segment a unique identifier and overwrites the variable names each loop (as far as I understand).

For example, in the loop, I create two segments (seg1 is yellow; seg2 is blue) and connect them with a U-joint. This loops 5 times to create 5 pairs of joined segments, but each pair is not connected to the next pair.

CaptureB.PNG

To connect pairs, I would need to connect seg2 to the next seg1 (e.g. between positions 2-3 in the figure), but because the loop overrides the variable names, I can't specify which seg1 to join with. My advisor and I searched how to create dynamic variable names to assign each segment a unique identifier, but it seems that is discouraged.

Do you have any ideas on how to solve this?

Thanks again,
CK
To unsubscribe from this group and stop receiving emails from it, send an email to projec...@googlegroups.com.

Radu Serban

unread,
Jun 20, 2020, 5:07:25 AM6/20/20
to projec...@googlegroups.com

Hi CK,

I'm not sure I understand why you would consider dynamic variable names.  That is definitely something to be discouraged.  But it's perfectly fine to reuse local variables in a loop.  As soon as you add a body or joint to the Chrono system, that local variable in the loop is not needed anymore and can be reused for the next segment.

Now, in your loop you should create both new bodies and the joints to connect them to the last body added in the previous iteration.   Maybe this is the source of your confusion.
Say you want to build a chain with the following topology
       [B1]-(j1)-[B2]-(j2)-[B1]-(j1)-[B2]-(j2)-[B1]-(j1)-[B2]-(j2)-[B1]-(j1)-[B2]-(j2)......[B1]
with two different types of bodies [B1] and [B2] and two different types of joints (j1) and (j2).
Then your "building block" would be
      (j1)-[B2]-(j2)-[B1]
and you could organize your construction along these lines:

b1 = create, add body to system
for i = 1:n_blocks
     b2 = create, add body to system
     j1 = create, connect b1 & b2, add joint to system
     b1 = create, add body to system
     j2 = create, connect b2 & b1, add joint to system
end

An alternative to this is to simply create lists of bodies and joints of appropriate size before the loop and then create your bodies and joints at increasing indices in those lists while you iterate in the loop (note that a list + an index in that list serves precisely as your "dynamic variable name").

You should also create your "millipede" in a straight initial configuration, that will make setting up the proper body and joint initial locations and orientations in the loop much easier.  I'm not sure why you have a relative pitch angle in your "building block".  Maybe because you just copied the configuration from the demo I pointed you to? 

Hope that this helps and puts you on the right track.

--Radu

To unsubscribe from this group and stop receiving emails from it, send an email to projectchron...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/projectchrono/91ce290e-a82a-4abe-b9d8-ae27bb1bb7e1o%40googlegroups.com.

CK Unsworth

unread,
Jun 22, 2020, 6:32:14 PM6/22/20
to ProjectChrono
Hi Radu,

That's exactly the feedback I was seeking and it fixed my issue, thanks so much. I was attempting a similar algorithm before, but with [B1]-(j1)-[B2] as my building block and the following loop:

for i = 1:n
     B1 = create, add body to system
     for i>1
            j2 = create, connect B2 &  B1, add joint to system
     B2 = create, add body to system
     j1 = create, connect B1 & B2, add joint to system
end

I was struggling to get the order of operations right and couldn't integrate j2. The screenshots from my previous post were taken while the simulation was running - the millipede started out straight and the images reflect b2 hinging around j1. I could have clarified that better, my apologies.

But your algorithm solved my issue and the simulation now works as desired:

Screenshot (599).png


Now I will use the Irrlicht app to ensure proper kinematics as you suggested. Thank you again for your detailed feedback, I appreciate all of your time and help!

Best,
CK

Reply all
Reply to author
Forward
0 new messages