modelica / ModelicaStandardLibrary

Free (standard conforming) library to model mechanical (1D/3D), electrical (analog, digital, machines), magnetic, thermal, fluid, control systems and hierarchical state machines. Also numerical functions and functions for strings, files and streams are included.
https://doc.modelica.org
BSD 3-Clause "New" or "Revised" License
452 stars 165 forks source link

Apply 1D Torque to 3D Revolute Joint without torque reaction #3761

Open dariomangoni opened 3 years ago

dariomangoni commented 3 years ago

I'd like to apply a torque to the Rotational Flange of a Revolute Joint. However, I don't want the torque reaction to be applied to the Support Flange of the Revolute Joint. The torque reaction is indeed counterbalanced elsewhere and not in the Revolute Joint itself. A real-world example is a vehicle wheel: the torque is given by a powertrain and transferred to the wheel by a shaft, so the torque reaction is not perceived on the wheelhub but on the powertrain mounts.

2021-02-23 14_48_02-OMEdit - OpenModelica Connection Editor

So, none of the above seems to be correct:

So, how can apply a Torque to a Revolute Joint without being forced to sense the counterbalanced torque directly on the joint? Since there is a Support Flange on the Revolute Joint one should be able to connect to it only if wanted, so the counterbalanced torque shouldn't be automatically balanced inside the Revolute Joint, am I wrong?

Full code here

dariomangoni commented 3 years ago

BTW, my proposal is to modify the Revolute joint in this way I don't know if it's worth to leave the "support" flange as it is right now or if this flange should be made solidal to frame_a

beutlich commented 3 years ago

That is the actual diff (w.r.t MSL 3.2.3) from the proposal if I figured it out correctly.

--- a/Modelica/Mechanics/MultiBody/Joints.mo
+++ b/Modelica/Mechanics/MultiBody/Joints.mo
@@ -260,6 +260,10 @@ Possible reasons:
     SI.Torque tau "Driving torque in direction of axis of rotation";
     SI.Angle angle "= phi_offset + phi";

+    parameter Modelica.Mechanics.MultiBody.Types.Axis m_seed={1,1,1}
+      "Vector linearly indipendent from n"
+      annotation (Evaluate=true);
+
   protected
     outer Modelica.Mechanics.MultiBody.World world;
     parameter Real e[3](each final unit="1")=Modelica.Math.Vectors.normalizeWithAssert(n)
@@ -279,6 +283,12 @@ Possible reasons:
       r=frame_a.r_0,
       R=frame_a.R) if world.enableAnimation and animation;

+    parameter Types.Axis e_m=Modelica.Math.Vectors.normalizeWithAssert(cross(e,m_seed))
+      "Versor linearly indipendent from n";
+
+      parameter Types.Axis e_p=Modelica.Math.Vectors.normalizeWithAssert(cross(e,e_m))
+      "Versor linearly indipendent from m and n";
+
   protected
     Modelica.Mechanics.Rotational.Components.Fixed fixed
       "support flange is fixed to ground"
@@ -303,18 +313,20 @@ Possible reasons:
     frame_b.r_0 = frame_a.r_0;

     if Connections.rooted(frame_a.R) then
-      R_rel = Frames.planarRotation(e, phi_offset + phi, w);
-      frame_b.R = Frames.absoluteRotation(frame_a.R, R_rel);
+      R_rel = Frames.absoluteRotation(frame_a.R, R_rel);
       frame_a.f = -Frames.resolve1(R_rel, frame_b.f);
-      frame_a.t = -Frames.resolve1(R_rel, frame_b.t);
+      frame_a.t*e_m = -Frames.resolve1(R_rel, frame_b.t)*e_m;
+      frame_a.t*e_p = -Frames.resolve1(R_rel, frame_b.t)*e_p;
     else
       R_rel = Frames.planarRotation(-e, phi_offset + phi, w);
       frame_a.R = Frames.absoluteRotation(frame_b.R, R_rel);
       frame_b.f = -Frames.resolve1(R_rel, frame_a.f);
-      frame_b.t = -Frames.resolve1(R_rel, frame_a.t);
+      frame_b.t*Frames.resolve1(R_rel, e_m) = -Frames.resolve1(R_rel, frame_a.t)*Frames.resolve1(R_rel, e_m);
+      frame_b.t*Frames.resolve1(R_rel, e_p) = -Frames.resolve1(R_rel, frame_a.t)*Frames.resolve1(R_rel, e_p);
     end if;

     // d'Alemberts principle
+    frame_a.t*e = 0;
     tau = -frame_b.t*e;

     // Connection to internal connectors
tobolar commented 3 years ago

We have some solution used for our automotive applications. I will cross-check the two approaches.

tobolar commented 3 years ago

Yet a simple solution is to set

frame_a.t = -Frames.resolve1(R_rel, frame_b.t + tau*e);

in the equations for "rooted(frame_a.R)", and correspondingly for equations applied when frame_a is not rooted. Thus, e_m and e_n were not needed.

A more advanced solution would be to additionally apply the support.tau on frame_a which would even enable to apply different torques on frame_a and frame_b. This would require several options for availability of the two 1D flanges as one can apply a 1D torque on support or axis, or both. The challenge is how to communicate these options to a user in an easy way.

dariomangoni commented 3 years ago

Thanks @tobolar for the very easy and effective change. My version was unusefully complex.

Also to me having support connected to frame_a sounds like a great idea. In my opinion it would suffice to set it as of Support type (not flange_a) and make it conditionally enabled by something like useAxisSupport. I think that the current behaviour of this joint is way more convoluted than this latter. (BTW, I already promptly adopted this version for my library)

tobolar commented 3 years ago

In my opinion it would suffice to set it as of Support type (not flange_a) ...

We shall use this name for backward compatibility first. But it shall be renamed later for a major version.

tobolar commented 3 years ago

Btw: this issue also concerns MultiBody.Joints.Prismatic.

dariomangoni commented 3 years ago

@tobolar thanks for the hint in looking into your fork. immagine

I think I understood your intentions, but I'll try to make some questions:

  1. 3D root option is nice, but I don't know if the average Modelica user could benefit from it; I'm worried that it might be misleading; but I think you have more ideas and use cases in mind that I have...
  2. meaning of 'fixed'; when a flange is set to be fixed it behaves like the support of the other one; i.e. the reaction torque is balanced on it automatically; the fixed flange in fact does not react to any external input; but if so, why leaving it visible/exposed? This leads to situation like revolute2 and revolute3 in which the frame_b does not sense what applied to axis but it only sense the balance over support.
  3. none fixed; this acts actually like a double revolute joint; the torque and the angle is given by the sum of the effects on both the flanges; that's quite flexible, but I think it misses to work properly in this very intuitive situation: immagine Since to none of the flanges had been given the phi=0 equation, one would need to add a Rotational.Components.Fixed to have it set.

My very first idea on this new Revolute joint was this: have a conditionally-enabled support that, if enabled, was always set to phi=0. Nothing else. If one wants to balance the torque, it should take care of it, like in the example above. However this approach:

I'll be glad to discuss it in person if someone is interested! Please drop me a line!

tobolar commented 3 years ago
  1. I agree, the idea of 3D root is too complicated with minimum benefit.
  2. Both flanges shall be visible. IMO the tests in ModelicaTest library are used for regression purposes to check full functionality of components. So revolute2 and revolute3 are possible but not typical cases.
  3. My first try, but not finished yet.

Your idea is good. In fact, we have to find some ballance between a generic and a feasible/understandable solution. I try to find more generic solution which shall work also in a case where revolute10 is flipped, i.e. the torque acts on support and its support is on axis. And frame_a connects the body and frame_b the world.