diff --git a/BobLib/Chassis/Suspension/Tires/BaseTire.mo b/BobLib/Chassis/Suspension/Tires/BaseTire.mo index 85e48e3..788983f 100644 --- a/BobLib/Chassis/Suspension/Tires/BaseTire.mo +++ b/BobLib/Chassis/Suspension/Tires/BaseTire.mo @@ -47,9 +47,6 @@ model BaseTire Modelica.Blocks.Sources.RealExpression realExpressionFy(y = 0) annotation( Placement(transformation(origin = {-90, -70}, extent = {{-10, -10}, {10, 10}}))); - Modelica.Blocks.Sources.Constant constantZero(k = 0) annotation( - Placement(transformation(origin = {-90, -90}, extent = {{-10, -10}, {10, 10}}))); - // Torque expressions Modelica.Blocks.Sources.RealExpression realExpressionMx(y = 0) annotation( Placement(transformation(origin = {-90, 54}, extent = {{-10, -10}, {10, 10}}))); @@ -61,17 +58,23 @@ model BaseTire Placement(transformation(origin = {-90, 26}, extent = {{-10, -10}, {10, 10}}))); Modelica.Mechanics.MultiBody.Forces.WorldForceAndTorque forceAndTorque( - resolveInFrame = Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.frame_b, + resolveInFrame = Modelica.Mechanics.MultiBody.Types.ResolveInFrameB.world, animation = not headless) annotation( Placement(transformation(origin = {-30, -50}, extent = {{-10, -10}, {10, 10}}))); protected + SI.Force contactForceWorld[3] + "Contact-patch cut force resolved in the world frame"; + SI.Force tireForceWorld[3] + "Tire shear force resolved in the road plane"; + SI.Torque tireTorqueWorld[3] + "Tire moment resolved about the road-plane axes"; Real[3] e_xw "Unit vector along wheel x-axis, resolved in world frame"; Real[3] e_yw "Unit vector along wheel y-axis, resolved in world frame"; Real[3] e_spin "Unit vector along wheel spin axis, resolved in world frame"; Real[3] e_zw "Unit vector along wheel z-axis, resolved in world frame"; Real[3] e_xg "e_xw projected on the xy-plane (ground) and normalized"; - Real[3] e_yg "e_yw projected on the xy-plane (ground) and normalized"; + Real[3] e_yg "Road-plane lateral axis orthogonal to e_xg"; // Velocity quantities (for slip calculation) Real[3] v_cp "Contact patch velocity in world frame"; @@ -82,7 +85,9 @@ protected equation // Normal load - Fz = noEvent(max(0, cpFrame.f[3])); + contactForceWorld = + Modelica.Mechanics.MultiBody.Frames.resolve1(cpFrame.R, cpFrame.f); + Fz = noEvent(max(0, contactForceWorld[3])); // World basis (from cpFrame) e_xw = Modelica.Mechanics.MultiBody.Frames.resolve1(cpFrame.R, {1, 0, 0}); @@ -92,7 +97,7 @@ equation // Ground-projected tire basis e_xg = normalize({e_xw[1], e_xw[2], 0}); - e_yg = normalize({e_yw[1], e_yw[2], 0}); + e_yg = {-e_xg[2], e_xg[1], 0}; // Inclination angle gamma = Modelica.Math.asin(noEvent(max(-1.0, min(1.0, e_zw[2])))); @@ -103,6 +108,19 @@ equation Vx = v_g[1]*e_xg[1] + v_g[2]*e_xg[2]; Vy = v_g[1]*e_yg[1] + v_g[2]*e_yg[2]; + // MF52 shear forces are defined in the road plane, using the same + // ground-projected axes as the slip kinematics. Tire moments follow the + // corresponding road axes, with aligning moment about the road normal. + tireForceWorld = + realExpressionFx.y*e_xg + + realExpressionFy.y*e_yg; + tireTorqueWorld = + realExpressionMx.y*e_xg + + realExpressionMy.y*e_yg + + realExpressionMz.y*{0, 0, 1}; + forceAndTorque.force = tireForceWorld; + forceAndTorque.torque = tireTorqueWorld; + // Slip model slipModel.Vx = Vx; slipModel.Vy = Vy; @@ -117,18 +135,6 @@ equation Line(points = {{-100, 0}, {-30, 0}})); connect(wheelModel.cpFrame, cpFrame) annotation( Line(points = {{0, -30}, {0, -100}}, color = {95, 95, 95})); - connect(realExpressionFx.y, forceAndTorque.force[1]) annotation( - Line(points = {{-78, -56}, {-42, -56}}, color = {0, 0, 127})); - connect(realExpressionFy.y, forceAndTorque.force[2]) annotation( - Line(points = {{-78, -70}, {-60, -70}, {-60, -56}, {-42, -56}}, color = {0, 0, 127})); - connect(constantZero.y, forceAndTorque.force[3]) annotation( - Line(points = {{-78, -90}, {-50, -90}, {-50, -56}, {-42, -56}}, color = {0, 0, 127})); - connect(realExpressionMx.y, forceAndTorque.torque[1]) annotation( - Line(points = {{-78, 54}, {-50, 54}, {-50, -44}, {-42, -44}}, color = {0, 0, 127})); - connect(realExpressionMy.y, forceAndTorque.torque[2]) annotation( - Line(points = {{-78, 40}, {-60, 40}, {-60, -44}, {-42, -44}}, color = {0, 0, 127})); - connect(realExpressionMz.y, forceAndTorque.torque[3]) annotation( - Line(points = {{-78, 26}, {-70, 26}, {-70, -44}, {-42, -44}}, color = {0, 0, 127})); connect(forceAndTorque.frame_b, wheelModel.cpFrame) annotation( Line(points = {{-20, -50}, {0, -50}, {0, -30}}, color = {95, 95, 95})); connect(wheelModel.hubFlange, hubFlange) annotation( diff --git a/Tests/BobLibTest/Regression/TireForceFrameSmoke.mo b/Tests/BobLibTest/Regression/TireForceFrameSmoke.mo new file mode 100644 index 0000000..5ba7a0b --- /dev/null +++ b/Tests/BobLibTest/Regression/TireForceFrameSmoke.mo @@ -0,0 +1,70 @@ +within BobLibTest.Regression; + +model TireForceFrameSmoke + + import SI = Modelica.Units.SI; + + inner parameter Real linkDiameter = 0.02; + inner parameter Boolean headless = true; + + parameter + BobLib.Records.VehicleRecord.Chassis.Suspension.Templates.Tire.Templates.PartialWheelRecord + pWheel( + R0 = 0.3, + rimR0 = 0.2, + rimWidth = 0.2, + staticAlpha = 15, + staticGamma = 10); + + model InclinedTire + + parameter + BobLib.Records.VehicleRecord.Chassis.Suspension.Templates.Tire.Templates.PartialWheelRecord + pTestWheel; + + extends BobLib.Chassis.Suspension.Tires.BaseTire( + pPartialWheel = pTestWheel, + realExpressionFy(y = 1000), + realExpressionMz(y = 100)); + + output SI.Force appliedForceWorld[3] = tireForceWorld; + output SI.Torque appliedTorqueWorld[3] = tireTorqueWorld; + + initial equation + assert( + abs(e_xg*e_yg) < 1e-12, + "Ground-projected tire axes must be orthogonal"); + assert( + abs(sqrt((600*e_xg + 800*e_yg)*(600*e_xg + 800*e_yg)) - 1000) < 1e-8, + "Combined road-plane force magnitude must be basis invariant"); + end InclinedTire; + + output SI.Force appliedForceWorld[3] = tire.appliedForceWorld; + output SI.Torque appliedTorqueWorld[3] = tire.appliedTorqueWorld; + + inner Modelica.Mechanics.MultiBody.World world( + n = {0, 0, -1}, + enableAnimation = false); + + Modelica.Mechanics.MultiBody.Parts.Fixed chassis( + r = {0, 0, 0.3}); + + InclinedTire tire(pTestWheel = pWheel); + +initial equation + assert( + abs(appliedForceWorld[3]) < 1e-8, + "Tire shear force must remain in the road plane"); + assert( + abs(sqrt(appliedForceWorld[1]^2 + appliedForceWorld[2]^2) - 1000) < 1e-8, + "Road-plane force magnitude must be preserved"); + assert( + abs(appliedTorqueWorld[3] - 100) < 1e-8, + "Aligning moment must act about the road normal"); + +equation + connect(chassis.frame_b, tire.chassisFrame); + + annotation( + experiment(StartTime = 0, StopTime = 0.001, Tolerance = 1e-6, Interval = 0.001)); +end TireForceFrameSmoke; diff --git a/Tests/BobLibTest/Regression/package.order b/Tests/BobLibTest/Regression/package.order index ddbeccb..abfefe7 100644 --- a/Tests/BobLibTest/Regression/package.order +++ b/Tests/BobLibTest/Regression/package.order @@ -1,2 +1,3 @@ MF52PureSlipSmoke +TireForceFrameSmoke VehicleSimAnimationOn diff --git a/Tests/modelica_initialization_baseline.csv b/Tests/modelica_initialization_baseline.csv index 31c420f..c0fa216 100644 --- a/Tests/modelica_initialization_baseline.csv +++ b/Tests/modelica_initialization_baseline.csv @@ -1,5 +1,6 @@ model,numeric_count,finite_count,nonfinite_count,names_sha256,sum,sum_abs,max_abs,values_sha256 BobLibTest.Regression.MF52PureSlipSmoke,8,8,0,a0fa6bc905c8ec7862790f47844443e6b3d0fbc901c2ddba34402dac7b1c9ed6,1291.2252864882239,1442.9166355632356,1367.049907523304,602021d8f6960ca5b5fdbb9d57887c8eca559b89200569fc13037adaa1b71c30 +BobLibTest.Regression.TireForceFrameSmoke,496,496,0,d71a3728741fa3d149b2dc7fc96ae2e63fcc4cf37c1cea25690d94fecdc8e781,4626.3120793459366,25075.180061240306,1000,9561bb1105f95f48ccf875f5c5edad7d08820527d9c746e63f938e2c8736506d BobLibTest.Regression.VehicleSimAnimationOn,1018,1018,0,bcf17a741d234b4273f3519e9a77fa72a0a2ad04dd966908a7d168f024cf4385,17285096.54280192,17286075.114064306,8400000,091bf5ae4529665cb8ecb40f00759f21bf3999ca31ebcb2aa707679ac743a332 BobLibTest.TestUtilities.TestMechanics.TestMultiBody.TestContactMechanics.TestGroundPhysics,75,75,0,494136a7a7c0f8b792cb3b044f96e92127a93c7eb042f412e4683ed40b67a423,138.2500000500003,139.25000015000086,128,0019557349df1e442f79cce3d2e75ecafdd8c2918ba114af267a7076af9b5afe BobLibTest.TestUtilities.TestMechanics.TestMultiBody.TestContactMechanics.TestGroundPhysicsRotatedFrame,3,3,0,fdf3ffca9af5c7e9474527b0256e59a25dd21d67d978aa439bb1d807f53d30f2,-1000.000252499937,1000.000252499937,1000.000252499937,825340ecd2192a9ad74b04f65e256164f0ee47c735ee73b57c5efc0205b460fa diff --git a/Tests/modelica_physics_baseline.csv b/Tests/modelica_physics_baseline.csv index eab2f25..edecd5b 100644 --- a/Tests/modelica_physics_baseline.csv +++ b/Tests/modelica_physics_baseline.csv @@ -7,6 +7,8 @@ BobLibTest.Regression.MF52PureSlipSmoke,0.01,Mz,-28.781188544190439,1e-6,1e-9,MF BobLibTest.Regression.MF52PureSlipSmoke,0.01,pneumaticTrail,0.021053502425769931,1e-9,1e-9,MF52 pure slip smoke pneumatic trail BobLibTest.Regression.MF52PureSlipSmoke,0.01,residualScrub,0,1e-9,1e-9,MF52 pure slip smoke residual scrub BobLibTest.Regression.MF52PureSlipSmoke,0.01,MzReconstructed,-28.781188544190439,1e-6,1e-9,MF52 aligning moment reconstruction +BobLibTest.Regression.TireForceFrameSmoke,0.001,appliedForceWorld[3],0,1e-9,1e-9,Tire shear force remains in the road plane +BobLibTest.Regression.TireForceFrameSmoke,0.001,appliedTorqueWorld[3],100,1e-9,1e-9,Tire aligning moment acts about the road normal BobLibTest.TestUtilities.TestMechanics.TestMultiBody.TestContactMechanics.TestGroundPhysicsRotatedFrame,0.01,contactForceWorld[1],0,1e-9,1e-9,rotated contact-frame force has no world x component BobLibTest.TestUtilities.TestMechanics.TestMultiBody.TestContactMechanics.TestGroundPhysicsRotatedFrame,0.01,contactForceWorld[2],0,1e-9,1e-9,rotated contact-frame force has no world y component BobLibTest.TestUtilities.TestMechanics.TestMultiBody.TestContactMechanics.TestGroundPhysicsRotatedFrame,0.01,contactForceWorld[3],-1000.000252499937,1e-6,1e-9,rotated contact-frame force remains world vertical diff --git a/Tests/modelica_runtime_baseline.csv b/Tests/modelica_runtime_baseline.csv index 3756900..020aa91 100644 --- a/Tests/modelica_runtime_baseline.csv +++ b/Tests/modelica_runtime_baseline.csv @@ -1,5 +1,6 @@ model,budget_s,description BobLibTest.Regression.MF52PureSlipSmoke,8,MF52 smoke physical baseline simulation +BobLibTest.Regression.TireForceFrameSmoke,15,Tire road-frame force regression simulation BobLibTest.TestUtilities.TestMechanics.TestMultiBody.TestContactMechanics.TestGroundPhysicsRotatedFrame,5,rotated contact-frame physical baseline simulation BobLibTest.TestVehicle.TestAero.TestCFDAeroMap,5,CFD aero map physical baseline simulation BobLibTest.TestVehicle.TestPowertrain.TestPowerLimitedMotor,25,Motor power and torque sign physical baseline simulation