Start a new topic

Tension in specific segment of a cable?

Is it possible to get the tension in a segment of a cable system, rather than just the maximum tension in the entire cable? I have a cable attached to a winch which then goes through several rings and finally ends at an attachment point. I need to be able to measure the tension in the cable at the starting point of the segment attached to the winch,  as it spools the cable in and out. How might I do this? 


Thanks

Corey


Hi Corey,


There is currently no way to get this information through the Generic Cable interfaces.

However, in 2018c we are adding a tension output to the GrabbingTool which could help here.

With this tool, if you grab a cable segment, you can read the max tension on the left and the right of the grab location. In your case you would want to use a very small mass in the part which is grabbing the cable.


An alternative approach would be to access the debug group of the cable system which contains all the constraints (VxConstraint) in the cable and locate the constraint that is closest to some point in space at which you want to measure the tension. From the constraint you can then read the tension force directly. Let me know if you want to explore this direction. I would then provide you with more instructions.


Cheers,

Daniel

Hi Daniel,

If I could get the constraint forces in the first section or first few sections of the segment attached to the winch, that would be ideal, because then I can compare it to the torque measured from the hinge constraint at the winch. 


Best,

Corey 

Hi Corey,


Maybe you can tell me a bit more about what you are actually looking for and why you need this data.

Because there is also the constraint which attaches the first cable part to the winch. This one also feels the tension...

Getting the data from this constraint is a bit more tricky as it is a custom constraint which is not one of the core constraint types. If we can get around drilling into the debug group and finding the tension there it would be easier. So maybe tell me a bit more about what you are trying to achieve here, just in case we can find a better solution.


Daniel

This is where I need to get the tension:

image


Or at least near this part of the cable, which ever is easiest.

Hi Daniel,

Will it be possible to get the tension in this part of the cable (shown in the picture above)? If not, how would you suggest we estimate the tension at this point in the cable?


Thanks

Corey

Hi Corey,


The only option you have (if you don't want to use the 2018c grabbing tool approach I mentioned), is to get the debug group from the dynamics extension in the generic cable (IDynamics::getDebugGroup), iterate over all constraints in there, and then find the constraint which is closest to the point you are interested in.

You can cast the constraint to VxCylindrical using dynamic_cast. The cable uses VxCylindrical internally.


Here is how to get the debug group from your IDynamics:

https://www.cm-labs.com/vortexstudiodocumentation/Vortex_Technical_Documentation/class_vx_sim_1_1_i_dynamics.html#ad

e3d040a4b91c293b0eea25bf7e6f26f


VxExtension* dynamicsCableExtension = ...
VxSim::VxSmartInterface<IDynamics> dynamicsInterface(dynamicsCableExtension);
VxDynamicsObject* debugGroup = dynamicsInterface->getDebugGroup();

  

On the VxDynamicsObject you can then go through all the constraints by going through all constraints in the object, and then going through all constraints in all assemblies of the object:


   

VxDynamicsObject* debugGroup = ...
VxConstraintSet registeredConstraints = debugGroup->getRegisteredConstraints();
// ... now go through all registered constraints an dynamic_cast the constraints to VxCylindrical. If it is a cylindrical, get the attachment positions and compare them with your point of interest via VxConstraint::getPartAttachmentPosition.
// Do the same for all constraints in all assemblies in the debug group (see below):
auto registeredAssemblies = debugGroup->getRegisteredAssemblies();
VxAssembly* someAssemblyInRegisteredAssemblies = ...
const VxConstraintSet& constraintsInAssembly = someAssemblyInRegisteredAssemblies->getConstraints();

   

Once you found the constraint of interest, you can get the tension force along the cylindrical axis like so:

VxCylindrical* c = ...
double tensionForce = c->getCoordinateControlForce(VxCylindrical::kLinearCoordinate);

 

This is quite tedious, but it would get the job done.


Daniel

Hi Daniel,

Could you explain how to dynamic_cast the constraints from the VxConstraintSet to VxCylindrical? 


Thanks,
Corey

Hi Corey,


The VxConstraintSet is a container. It is a set of constraint pointers (VxConstraint*).

To go through them you can loop over them as follows:  

const VxConstraintSet& someSet = ...
for(auto iter = someSet.begin(), end = someSet.end(); iter != end; ++iter)
{
    VxConstraint* cons = *iter;
    VxCylindrical* cyl = dynamic_cast<VxCylindrical*>(cons);
    if (cyl != nullptr)
    {
        // ...cons is a cylindrical...
    }
}
 

   or, using C++11 syntax with range-based for loop (see https://en.cppreference.com/w/cpp/language/range-for):

 

auto& constraints = assembly->getConstraints();
for (auto cons : constraints)
{
    auto cyl = dynamic_cast<VxCylindrical*>(cons);
    if (cyl != nullptr)
    {
        // ...cons is a cylindrical...
    }
}

 

Cheers,

Daniel


Hi Daniel,

I think I'm very close to getting this to work. What I have right now is this:


VxReal tethertension;

  VxCylindrical* tethercylindrical;

  VxSim::VxSmartInterface<IDynamics> dynamicsInterface(dynamicsCableExtension);

  VxDynamicsObject* debugGroup = dynamicsInterface->getDebugGroup();

  auto registeredAssemblies = debugGroup->getRegisteredAssemblies();

  auto assemblyiter = registeredAssemblies.begin() + 1;

  VxAssembly* someassembly = *assemblyiter;

  const VxConstraintSet& constraintsinassembly = someassembly->getConstraints();

  std::cout << "Size of constraint set in assembly is " << constraintsinassembly.size() << std::endl;

  for (auto iter = constraintsinassembly.begin(), end = constraintsinassembly.end(); iter != end; ++iter)

  {

   VxConstraint* cons = *iter;

   if (iter == constraintsinassembly.begin()) {

    VxCylindrical* cyl = dynamic_cast<VxCylindrical*>(cons);

 

    if (cyl != nullptr)

    {

 

     // ...cons is a cylindrical...

     tethercylindrical = cyl;

     tethertension = tethercylindrical->getCoordinateControlForce(VxCylindrical::kLinearCoordinate);

     std::cout << "Constraint force is " << tethertension << std::endl;

    }

   }

  }


So I'm trying to get the constraint force from the first constraint in the 2nd registered assembly.

At every timestep I have: 


while((application->update()) && (currentTime<finalTime))

        { ......

         tethertension = tethercylindrical->getCoordinateControlForce(VxCylindrical::kLinearCoordinate);

         .......

}


The tethertension is written to a file. When I check the output, it's zero at every timestep and I'm not sure why. It seems like I have just one little thing missing and I'm not sure what it is. 


Let me know what you think.


Best,

Corey

That's looking pretty good!

I think the issue you are running into is because the cylindrical joint you are picking up might be the first one directly at the top of the cable at the junction to the pulley/winch. This joint is set to "free" control for the linear coordinate and an internal, special cable systems joint models the connection of the cable parts to the pulley/winch. That's why there is no force reported for this coordinate. It actually does not add any force.

So, you should just skip this cylindrical by adding the following condition after the dynamic cast:


 

    if (cyl != nullptr)
    {
        if (cyl->getControl(VxCylindrical::kLinearCoordinate) == VxConstraint::kControlLocked)
        {
            //... found a good cylindrical constraint ...
        }
    }

 Use this constraint to measure the tension.


Cheers,

Daniel

Hi Daniel,

Thanks a lot, that worked! I have a few more questions about the constraint force. I included a picture of the full system to explain it a bit better. The tether starts at a winch and passes through several rings at the center and around the perimeter of the net.

image


 So I'm trying to read the tension at the starting point (the point just after the connection to the winch) in the tether as the winch pulls the net closed (or as the winch is free to spool the tether out). Here's a picture of the constraint when I run the simulation:

image


I'm comparing the constraint force with the kMaxTensionID of the cable system. The values are similar at each timestep, but sometimes the constraint force is negative (for example MaxTension = 0.249023 and constraintforce =  -0.248937 ) . This just means that the direction of the constraint force is opposite, correct? A negative constraint force does not mean it is under compression? Is it safe to take the absolute value of the constraint force as the tension in that section of the cable?


Thanks again for all your help, I really appreciate it!


Corey



1 person likes this

That's great. I am glad I could help.


Regarding the sign of the force:


The convention in the cable requires you to flip the sign of the control force in the cable joint in order to get the tension value. The scalar force returned by the cylindrical constraint for the linear coordinate is actually the compression force by convention.

When exposing the maximum tension in the cable system extension, we do this conversion for you under the hood.

So, don't use the absolute, just flip the sign to calculate the tension. This way, you can still detect when the cable is under compression (negative tension).


Just to give you a better understanding of the definition of the control force and the coordinate frame of constraints, I invite you to read up on the link below.

In a nutshell, the scalar force which you are reading here (it's the Lagrange multiplier actually) is applied along the axis of the coordinate. And the axis of the coordinate is defined by the parts' constraint attachments. Here is a description of this scenario for the cylindrical:

https://www.cm-labs.com/vortexstudiodocumentation/Vortex_User_Documentation/Content/Concepts/cns_type_cylindrical.html?Highlight=cylindrical


So, if the scalar force of the cylindrical's linear coordinate is negative, it is acting in the negative direction of the first axis in the first part's constraint attachment (that's a mouthful ;)), that is, vector u_0 in the image from the link above.



Cheers,

Daniel



Ahh okay, I understand now, thanks for the link. Since we're on this topic, is it possible to eliminate any compression force in the cable? A thin, flexible rope shouldn't be able to sustain compression - a rope can't push anything. So to make my model more accurate I think compression should be neglected. When I set the cable parameter kCompressionMaxForceID near zero, say 0.1, the simulation blows up, like this: 

image

I figure this has something to do with the number of sections in each segment of the cable. 

So what exactly happens when kCompressionMaxForceID is exceeded or if it is set to zero?

Best,

Corey

Hi Daniel,

I have a couple more questions. Since I have a winch spooling the cable in and out, the number of constraints in the first segment is changing with time. I'm basically trying to mimic a tension sensor using the constraint force measurement (i.e, measuring the tension at a point as the cable passes through that point, rather than measuring from the same point in the cable at each iteration) -- so the constraint force I measure will be coming from a different constraint each time. I need to know where the numbering of the constraints in the debug group starts; at the first attachment point (the winch) or at the last attachment point? So far I've been trying to update the constraint force measurement at each timestep, like this:

while((application->update()) && (currentTime<finalTime)) {

// ...

     VxSim::VxSmartInterface<IDynamics> dynamicsInterface(dynamicsCableExtension);

     VxDynamicsObject* debugGroup = dynamicsInterface->getDebugGroup();

     auto registeredAssemblies = debugGroup->getRegisteredAssemblies();

     auto assem_iter = registeredAssemblies.begin() + 1;

     VxAssembly* someassembly = *assem_iter;

     const VxConstraintSet& constraintsinassembly = someassembly->getConstraints();

     auto cons_iter = constraintsinassembly.end() - 2;

     VxConstraint* cons = *cons_iter;

     VxCylindrical* cyl = dynamic_cast<VxCylindrical*>(cons);


     if (cyl != nullptr) {

      // ......

 

     }

     // ... 

}


However, its throwing an Exception immediately: 

Exception thrown: read access violation.

**this** was 0x2BC2776F0.


It has to do with the dynamic_cast<VxCylindrical*> line. When I comment it out, the simulation runs but I need it to get the force. 


Let me know if you have any suggestions


Best,

Corey

Login to post a comment