Start a new topic
Answered

Measure cable forces and torques at attachment

Hi, 


I’m working on a tethered ROV and need to study the influence of the cable on the ROV. I need to assess the forces vector and torques vector between the cable and the attachment point.


On previous exchanges with Vortex support I learned that I can access the control force and some equations in the constraints of the cable. 

I start to access all the constraints from universe :

constraints = self.universe.constraints

 Then I test if they are valid, if they're linked to the cable I want to study and I select the one that is attached to the ROV:  

    for c in constraints:
       if not len(dir(c)): 
       if c.enable and self.cable_droit_name in c.name:
          if c.type == cylindrical.type: 
             if "Attachment_FirstExtremity" in c.name:

Then, I access the forces and torques: 

c.coordinates[0].currentStateControlForce
c.equations[0].lastForce
c.equations[1].lastForce
c.coordinates[1].currentStateControlForce
c.equations[2].lastForce
c.equations[3].lastForce

 My problem is that I don't see along/around which axis those forces/torques are defined.


To try to understand how those forces are defined I designed a small example by hanging a mass to a cable attached to a fixed part. This fixed part is either vertical (configuration 1), turned of 45° around y axis (configuration 2) or of 90° around y axis (configuration 3). The cable fixation to the part is a flexible attachment with the attachment direction in the same direction as the part. 

image



I started to measure de forces and torques in those two configurations with Matlab Simulink to compare the results with Vortex. In Simulink, the forces are expressed in the 

part reference frame (xa,ya,za).


For the configuration 1:

In Simulink, I measure: Forces = [0;0;-1.095] Torques = [0;0;0], which makes sense.

In Vortex, I measure : 

c.coordinates[0].currentStateControlForce = 1,095

c.equations[0].lastForce = 0

c.equations[1].lastForce = 0

c.coordinates[1].currentStateControlForce = 0

c. equations[2].lastForce = 0

c.equations[3].lastForce = 0

Which would show that the c.coordinates[0].currentStateControlForce is along the z axis wich is the same for the global frame (z0) and the part frame (za) in this configuration. 

For the configuration 2:

In Simulink, I measure: Forces=[0.7745;0;-0.7746] Torques=[0;-0.01372;0]

In Vortex, I measure : 

c.coordinates[0].currentStateControlForce = 1,077

c.equations[0].lastForce = 0

c.equations[1].lastForce = 0,198

c.coordinates[1].currentStateControlForce = 0

c. equations[2].lastForce = 0

c.equations[3].lastForce = -0,014

There, the c.coordinates[0].currentStateControlForce does not seem to be along the z axis of the part nor of the global frame.  

The c.equations[3].lastForce seems to correspond to the torque around the y axis. 


For the configuration 3:

In Simulink, I measure: Forces=[1.095;0;0] Torques=[0;-0.02732;0]

In Vortex, I measure : 

c.coordinates[0].currentStateControlForce = 1,044

c.equations[0].lastForce = 0

c.equations[1].lastForce = 0,332

c.coordinates[1].currentStateControlForce = 0

c.equations[2].lastForce = 0

c.equations[3].lastForce = -0,027

This makes me think that the c.equations[0].lastForce would be along the y axis. But I don't know for the others. And it would confirm that the c.equations[3].lastForce may be around the y axis. 


To see if the forces depend on the global reference frame or not, I tried to turn the assemblies aroung the z axis. This is the result when I turn the configuration 2 of 90° around the z axis:

c.coordinates[0].currentStateControlForce = 1,077

c.equations[0].lastForce = 0

c.equations[1].lastForce = 0,198

c.coordinates[1].currentStateControlForce = 0

c. equations[2].lastForce = 0

c.equations[3].lastForce = 0,014

The forces and torques are the same as with the not turned configuration 2, which makes me think that they are not expressed in the global frame, except for the c.equations[3].lastForce = 0,014 whose sign is reversed. I struggle to understand why. 


If I activate the view of the constraints in the cable, I can see the orientation of the attachment constraint which is not in the same direction as the part. Maybe the forces are expressed in this frame ? But then is there a way to know the exact orientation of this frame according to the part's frame or of the universe frame ? This is the only way I could analyze those values.  

image



If I directly access the forces applied to the ROV, I would have all the forces (like thrusters, drag, buoyancy,...) and not only the forces from the cable.


Thanks in advance for your help. 
Regards,

Ornella


Best Answer

Hi Ornella,


The constraints provide an API to get the constraint attachments. These should theoretically allow you to understand along which direction or around which axes the scalar forces that are returned by the constraint every frame are applied.

I am not sure I understand the problem at this level. The constraints always behave the same. So there might be a switch of order of the parts in the constraint, which would cause the constraint force to be flipped, but since you can get access to the axes of the constraints you should be able to make sense of the forces.


Here is the definition of the frames of a cylindrical which is always the same:

https://www.cm-labs.com/vortexstudiodocumentation/Vortex_User_Documentation/Default.htm#Concepts/cns_type_cylindrical.html?Highlight=Cylindrical


So, the forces are always specified with respect to the constraint attachments that are set up. And the constraint attachment is available in the VxConstraint API.

See here for all the available information:

https://www.cm-labs.com/vortexstudiodocumentation/Vortex_Technical_Documentation/class_vx_1_1_vx_constraint.html#a1bda1a446e6bbe1dab667ceadfcc133e


Some of these functions might not be exposed via pyvx unfortunately.


So, ultimately, there might be an easier solution for what you are looking for. If I understand you correctly, you are interested in the forces applied at the ROV/cable attachment, correct?

If that is the case, you could simply add an additional part and constraint between the cable end point and the ROV and then measure the applied forces at this constraint level. This constraint would be accessible with all the field outputs of high level constraints in the editor.

Would that be a viable solution?


Cheers,

Daniel


Just a little correction for the second par of the script, a line was missing : 

  

    for c in constraints:
       if not len(dir(c)): 
          continue
       if c.enable and self.cable_droit_name in c.name:
          if c.type == cylindrical.type:
             if "Attachment_FirstExtremity" in c.name: 

  

I thought I found the solution but it's not working when I turn the assemblies around the z axis. 


It seems that the forces are expressed in the "part0" of the constraint, which is the first element of the cable linked to the fixed part. 

In this frame, it seems that :

c.coordinates[0].currentStateControlForce     is along z axis as on conf1 its value was the weight of the system

c.equations[0].lastForce                                     is along y axis as its value was always 0

c.equations[1].lastForce                                     is along x axis

c.coordinates[1].currentStateControlForce     is along z axis

c. equations[2].lastForce = 0                             is along x axis

c.equations[3].lastForce = 0                              is along y axis as its value was not 0 for conf 2 and conf 3


I could access the transform matrix of part0 and apply its rotation matrix on those vectors, which gave me the forces and torques in the world frame. 

I then applied the inverse of the rotation matrix of the fixed part to those vectors to obtain the forces and torques in the fixed part reference frame. 

It seemed to work except for an inverted sign on z forces and y torques. 

image



I then tried to turn my assemblies around the z axis to see if this solution was robust, but it wasn't at all and the obtained values didn't make sense at all.

image


  

This is the code I did for those transforms:

                part0 = c.attachments[0].part
                part1 = c.attachments[1].part 

                transform_constraint = part0.transform
                rotation_matrix_constraint = np.zeros((3,3))
                for i in range(3):
                    for j in range (3):
                        rotation_matrix_constraint[i,j] = (transform_constraint[i])[j]

                transform_attache = part1.transform
                rotation_matrix_attache = np.zeros((3,3))
                for i in range(3):
                    for j in range (3):
                        rotation_matrix_attache[i,j] = (transform_attache[i])[j]
                rotation_matrix_attache_inv = np.linalg.inv(rotation_matrix_attache)

                Forces = VxSim.VxVector3(0,0,0)
                Forces[2] = c.coordinates[0].currentStateControlForce
                Forces[1] = c.equations[0].lastForce
                Forces[0] = c.equations[1].lastForce
                # Transform to world frame:
                Forces = Array_to_vector3((np.dot(rotation_matrix_constraint,Vector3_to_array(Forces))).T)
                # Transform to fixed part frame:
                Forces = Array_to_vector3((np.dot(rotation_matrix_attache_inv,Vector3_to_array(Forces))).T)
                self.outputs.Forces.value = VxVector3(Forces)

                Moments = VxSim.VxVector3(0,0,0)
                Moments[2] = c.coordinates[1].currentStateControlForce
                Moments[0] = c.equations[2].lastForce
                Moments[1] = c.equations[3].lastForce
                # Transform to world frame:
                Moments = Array_to_vector3((np.dot(rotation_matrix_constraint,Vector3_to_array(Moments))).T)
                # Transform to fixed part frame:
                Moments = Array_to_vector3((np.dot(rotation_matrix_attache_inv,Vector3_to_array(Moments))).T)
                self.outputs.Moments.value = VxVector3(Moments)

   

Hi,


After looking at you code and also at our code. We have found a bug in our code. The names of the first and last constraint in a Flexible segment are mixed.


 If you search for the constraint with "Last" in its name you will find the first constraint and have the force and torque you are expecting.  (See python code below)

Note: The fix will be available in the next release of Vortex so you will need to update your script when you will update to the new version.

    for c in constraints:
       if not len(dir(c)): 
          continue
       if c.enable and self.cable_droit_name in c.name:
          if c.type == cylindrical.type:
            # There is a bug in the name assignation, between the first and last constraint, the names are interverted
            # The work around is to search for the word "Last" to find the first constraint
            # Note: This will be fixed in the next release
             if "Attachment_LastExtremity" in c.name: 

 

Regards, 


Remi



Hi Rémi, Thanks for your answer. Yeah I already found this little bug but it's not my problem here I guess. I created my cable from the mass to the fixed part. So the first extremity would logically be the one at the mass but it is the one at the fixed part on top. I already noticed that by printing the position of the parts of the contraint. So I should already be looking at the right constraint. But then I'm wondering along/which axis the forces and torques of this constraint are defined. Regards, Ornella

Hi Ornella,


For a VxCylindrical constraint, you have the primary axis along which you have the control force and around which you have control torque and 2 equation axes. This primary axis for the first constraint of a cable is along the first part on the cable.  The secondary axis is automatically generated and will start along the z+ world axis if the cable is horizontal or along the y+ world axis if the cable is vertical.  The third axis will be simply the cross product of the primary axis with the secondary axis. But as soon as there is some orientation to the cable before the first step (before the cable is build) the secondary axis can have a different orientation with a complex set of condition but will always be perpendicular to the primary axis. 


Since the axes are expressed in the local frame of the part, the axis will follow the part and the force and torque will follow the axes.


The axis of the force for the first constraint should be as follow. The  currentStateControlForce  will always be along the first part of the cable and the  equations[0].lastForce and equations[1].lastForce will be perpendicular to currentStateControlForce and will also be perpendicular to each other. Since the orientation of equations[0].lastForce  and equations[0].lastForce are automatically generated, we can only be sure that they will be perpendicular to the axis of currentStateControlForce  and perpendicular to each other. 



Regards,


Remi

Hi Rémi, 


Thanks for your answer. 
So, if I understand correctly, the forces have their own reference frame which is attached to the reference frame of the part0 of the constraint but they don't necessarily have the same orientation ? 

And there's no way to access the orientation of the forces reference frame according to the world during simulation ?


But if I start the simulation in a specific configuration (cable vertical or horizontal) I can know the initial orientation of the forces reference frame, as long as the transform matrix of the part so I can determine the transform between the forces and the part, which should then stay the same during the whole simulation ? 


If not all the cable is horizontal but the portion I'm interested in is horizontal at the begining of the simulation (as in the image below), can I consider that the secondary axis will start along the z+ world axis  as you stated ? 

image


The only thing I can be sure of is that the currentStateControlForce is along the axis of the cable ? I thought it was the same if I use a grabbing tool to measure the tension in the cable at a specific point. But I compared the tension of a grabbing tool placed at the attachment point with the currentStateControlForce for all my configurations and their values are slightly different. Plus, it seems that the grabbing tool works only in traction and not compression (the fourth configuration is with the system reversed : mass on top, fixed point below) as its value is 0 for the last configuration. I also notice that force in the reversed configuration is opposed to the force in the first configuration. Even if they should both be in -Z direction. Is it because the second one is in compression or just because the cable direction (from mass to fixed part) is reversed in the last configuration ?  

image


Regards, 

Ornella

Answer

Hi Ornella,


The constraints provide an API to get the constraint attachments. These should theoretically allow you to understand along which direction or around which axes the scalar forces that are returned by the constraint every frame are applied.

I am not sure I understand the problem at this level. The constraints always behave the same. So there might be a switch of order of the parts in the constraint, which would cause the constraint force to be flipped, but since you can get access to the axes of the constraints you should be able to make sense of the forces.


Here is the definition of the frames of a cylindrical which is always the same:

https://www.cm-labs.com/vortexstudiodocumentation/Vortex_User_Documentation/Default.htm#Concepts/cns_type_cylindrical.html?Highlight=Cylindrical


So, the forces are always specified with respect to the constraint attachments that are set up. And the constraint attachment is available in the VxConstraint API.

See here for all the available information:

https://www.cm-labs.com/vortexstudiodocumentation/Vortex_Technical_Documentation/class_vx_1_1_vx_constraint.html#a1bda1a446e6bbe1dab667ceadfcc133e


Some of these functions might not be exposed via pyvx unfortunately.


So, ultimately, there might be an easier solution for what you are looking for. If I understand you correctly, you are interested in the forces applied at the ROV/cable attachment, correct?

If that is the case, you could simply add an additional part and constraint between the cable end point and the ROV and then measure the applied forces at this constraint level. This constraint would be accessible with all the field outputs of high level constraints in the editor.

Would that be a viable solution?


Cheers,

Daniel


1 person likes this

Hi Daniel, 


Thanks for your answer. 
So, if I understand you correctly, the forces of a constraint are defined along the axis of the part0 of this constraint ? Meaning that for example, the constraint.coordinates[0].currentStateControlForce would be along the u0 axis shown in the drawing of your first link ? Because I can access the transform matrix of the part0 and I tried to apply it on the forces values but the result didn't seem correct, as stated in my 3rd message here. 


Yes, exactly, I'm interested in the forces applied by the cable to the ROV at attachment point. 

I guess it would be a viable solution. So I would add a part, fix it with and RPRO constraint to the ROV on one side and attach the cable to this part with a flexible attachment point and then observe the outputs of the RPRO constraint ? 


Cheers,

Ornella

RPRO constraint: Yes, precisely!

If that works for you, I think it is the most efficient way to achieve your goal. What do you think?


Cheers,
Daniel

Hi Daniel, 


I tried with the RPRO constraint, it seems to work perfectly, and this solution is much easier than to access the cable internal properties. 

Thank you very much. 


Cheers, 
Ornella 

Hi Ornella,


That's great to hear! That's what I thought.


Cheers,

Daniel

Login to post a comment