model RollingWheel "Joint (no mass, no inertia) that describes an ideal rolling wheel (rolling on the plane z=0)"
import Modelica.Mechanics.MultiBody.Frames;
Modelica.Mechanics.MultiBody.Interfaces.Frame_a frame_a "Frame fixed in wheel center point. x-Axis: upwards, y-axis: along wheel axis"
annotation (Placement(transformation(extent = {
{-16, -16},
{16, 16}})));
parameter SI.Radius wheelRadius "Wheel radius";
parameter StateSelect stateSelect = StateSelect.always "Priority to use generalized coordinates as states"
annotation (
HideResult = true,
Evaluate = true);
SI.Position x(start = 0, stateSelect = stateSelect) "x-coordinate of wheel axis";
SI.Position y(start = 0, stateSelect = stateSelect) "y-coordinate of wheel axis";
SI.Position z;
SI.Angle angles[3](start = {0, 0, 0}, each stateSelect = stateSelect) "Angles to rotate world-frame into frame_a around z-, y-, x-axis"
annotation (Dialog(
group = "Initialization",
showStartAttribute = true));
SI.AngularVelocity der_angles[3](start = {0, 0, 0}, each stateSelect = stateSelect) "Derivative of angles"
annotation (Dialog(
group = "Initialization",
showStartAttribute = true));
SI.Position r_road_0[3] "Position vector from world frame to contact point on road, resolved in world frame";
SI.Force f_wheel_0[3] "Contact force acting on wheel, resolved in world frame";
SI.Force f_n "Contact force acting on wheel in normal direction";
SI.Force f_lat "Contact force acting on wheel in lateral direction";
SI.Force f_long "Contact force acting on wheel in longitudinal direction";
SI.Position err "|r_road_0 - frame_a.r_0| - wheelRadius (must be zero; used for checking)";
protected
Real e_axis_0[3] "Unit vector along wheel axis, resolved in world frame";
SI.Position delta_0[3](start = {0, 0, -wheelRadius}) "Distance vector from wheel center to contact point";
Real e_n_0[3] "Unit vector in normal direction of road at contact point, resolved in world frame";
Real e_lat_0[3] "Unit vector in lateral direction of wheel at contact point, resolved in world frame";
Real e_long_0[3] "Unit vector in longitudinal direction of wheel at contact point, resolved in world frame";
SI.Position s "Road surface parameter 1";
SI.Position w "Road surface parameter 2";
Real e_s_0[3] "Road heading at (s,w), resolved in world frame (unit vector)";
SI.Velocity v_0[3] "Velocity of wheel center, resolved in world frame";
SI.AngularVelocity w_0[3] "Angular velocity of wheel, resolved in world frame";
SI.Velocity vContact_0[3] "Velocity of wheel contact point, resolved in world frame";
Real aux[3];
equation
assert(abs(e_n_0 * e_axis_0) < 0.99, "Wheel lays nearly on the ground (which is a singularity)");
Connections.root(frame_a.R);
0 = delta_0 * e_axis_0;
0 = delta_0 * e_long_0;
0 = vContact_0 * e_lat_0;
0 = vContact_0 * e_long_0;
0 = wheelRadius - delta_0 * cross(e_long_0, e_axis_0);
aux = cross(e_n_0, e_axis_0);
delta_0 = r_road_0 - frame_a.r_0;
e_axis_0 = Frames.resolve1(frame_a.R, {0, 1, 0});
e_lat_0 = cross(e_long_0, e_n_0);
e_long_0 = aux / Modelica.Math.Vectors.length(aux);
e_n_0 = {0, 0, 1};
e_s_0 = {1, 0, 0};
err = Modelica.Math.Vectors.length(delta_0) - wheelRadius;
f_wheel_0 = f_n * e_n_0 + f_lat * e_lat_0 + f_long * e_long_0;
r_road_0 = {s, w, 0};
v_0 = der(frame_a.r_0);
w_0 = Frames.angularVelocity1(frame_a.R);
der_angles = der(angles);
vContact_0 = v_0 + cross(w_0, delta_0);
frame_a.R = Frames.axesRotations({3, 2, 1}, angles, der_angles);
frame_a.r_0 = {x, y, z};
zeros(3) = frame_a.f + Frames.resolve2(frame_a.R, f_wheel_0);
zeros(3) = frame_a.t + Frames.resolve2(frame_a.R, cross(delta_0, f_wheel_0));
annotation (
Icon(
coordinateSystem(
preserveAspectRatio = true,
extent = {
{-100, -100},
{100, 100}}),
graphics = {
Rectangle(
extent = {
{-100, -80},
{100, -100}},
fillColor = {175, 175, 175},
fillPattern = FillPattern.Solid),
Text(
extent = {
{-150, 120},
{150, 80}},
lineColor = {0, 0, 255},
textString = "%name"),
Ellipse(
extent = {
{-80, 80},
{80, -80}},
fillColor = {255, 255, 255},
fillPattern = FillPattern.Solid)}),
Documentation(info = "<html>\n<p>\nA joint for a wheel rolling on the x-y plane of the world frame.\nThe rolling contact is considered being ideal, i.e. there is no\nslip between the wheel and the ground. This is simply\ngained by two non-holonomic constraint equations on velocity level\ndefined for both longitudinal and lateral direction of the wheel.\nThere is also a holonomic constraint equation on position level\ngranting a permanent contact of the wheel to the ground, i.e.\nthe wheel can not take off.\n</p>\n<p>\nThe origin of the frame frame_a is placed in the intersection\nof the wheel spin axis with the wheel middle plane and rotates\nwith the wheel itself. The y-axis of frame_a is identical with\nthe wheel spin axis, i.e. the wheel rotates about y-axis of frame_a.\nA wheel body collecting the mass and inertia should be connected to\nthis frame.\n</p>\n\n<h4>Note</h4>\n<p>\nTo work properly, the gravity acceleration vector g of the world must point in the negative z-axis, i.e.\n</p>\n<blockquote><pre>\n<span style=\"font-family:'Courier New',courier; color:#0000ff;\">inner</span> <span style=\"font-family:'Courier New',courier; color:#ff0000;\">Modelica.Mechanics.MultiBody.World</span> world(n={0,0,-1});\n</pre></blockquote>\n</html>"));
end RollingWheel;