Tutorial - Vehicle Dynamics
Learning Objectives
After completing this chapter readers will be able to:
a
b
c
Optimal Control problem without road gemetry
define monodimensional OCP problem which does not require a road geometry description or a reference line
Optimal Control problem with road gemetry
Single-Track Vehicle Model with Road2D Class
Note
You can download this example as a Maple sheet:
02-SingleTrack-road-ocp.zip
.
In this example we want to solve the problem of a car travelling on a road in minimum time. We adopt the well established Single-Track vehicle model to model the motion of a four wheels passenger car. The tire forces are generated using a simplified single-point contact model. The Single-Track vehicle model is described by three equations of motion (longitudinal, lateral and yaw equilibria); two first-order dynamics equations are added to model the relaxation length of the lateral slips. Since the equations are quite long, for the sake breviness we will not report them here.
As first introduced in [CDLLF99], when dealing to minimum-time optimal control problem along a path, the curvilinear description of the road comes in handy. The vehicle pose can be described in curvilinear coordinates with respect to the centerline of the path. The curvilinear coordinates are:
curvilinear abscissa \(s\): it is the distance along the reference line of the closest point from the vehicle position. The reference line is usually the centerline of the road we want to represent
lateral distance \(n\): the lateral minimum distance of hte vehicle from the reference line (orthogonal to the tangent to the reference line in the point at abscissa \(s\))
relative heading \(\xi(\alpha)\) in Figure shows the curvilinear coordinates to describe the road geometry and the position of the vehicle: relative angle between the heading of the vehicle and the direction of the tangent to the reference line in the point at abscissa \(s\)
A scheme of the curvilinear description of the vehicle pose is presented in Figure shows the curvilinear coordinates to describe the road geometry and the position of the vehicle. The interested reader can refer to [CDLLF99] for further details.
Curvilinear coordinates description of the vehicle pose.
Curvilinear coordinates introduces three more ordinary differential equations to the model dynamical system:
From (14) we can obtain the relationship between the time, which is the current independent variable of the dynamical system, and the curvilinear abscissa \(s\):
The relationship (15) is used to change the independent variable from time \(t\) to curvilinear abscissa \(s\). Notice that by integrating (15) from the initial values to the final value value of the abscissa we obtain the final time that took the vehicle to complete the maneuver along the road described by the curvilinear coordinates. Consequently, by placing expression (15) in the Lagrange term, we can straightforwardly minimize the final time of the maneuver.
Another vantage of using curvilinear coordinates is that they greatly simplify the description of the road and its left and right limits. The road can be described by the curvature of the centerline as a function of the abscissa \(s\), and by the width of the left and right road limits. Since the lateral distance \(n\) is one state of the problem, it can be simply bounded between the (arbitrarly variable) widths of the right and left road limits, in order to constraint the vehicle to remain inside the road lane.
The Road2D Class
The XOptima
package implements a useful class to easily create a road
description, the Road2D
class. Firstly, we define the road using the
list road_data_init
. We must define the initial orientation theta0
and cartesian coordinates x0
, y0
of the road. Default orientation of
the curvilinear reference frame is ISO “z up”, as \((x_r-y_r)\) in Figure shows the curvilinear coordinates to describe the road geometry and the position of the vehicle, but can be
changed to SAE “z down”. Then an array segments
of all the road
segments must be provided. Each segment is a list containing the grid
size, curvature, lenght, and left and right widths of the road. If
curvature
is provided, a circle arc segment with the prescribed
curvature will be build. If initialCurvature
and finalCurvature
are
provided instead, a clothoid segment with the prescribed initial and
final curvatures will be built (see [BF15] for further
details on clothoids and the clothoid library).
grid_size_base := 0.5:
W0 := 5:
road_data_init := [
"theta0" = 0,
"s0" = 0,
"x0" = 0,
"y0" = 0,
"is_SAE" = false,
"segments" = Array(
[
table([ "length" = 10, "gridSize" = 0.1, "curvature" = 0, "rightWidth" = W0/2, "leftWidth" = W0/2 ] ),
table([ "length" = 90,"gridSize" = grid_size_base, "curvature" = 0, "rightWidth" = W0/2, "leftWidth" = W0/2 ] ),
table([ "length" = evalf(Pi*50),"gridSize" = grid_size_base, "initialCurvature" = 1/50.,"finalCurvature" = 1/50.,
"rightWidth" = W0/2, "leftWidth" = W0/2 ] ),
table([ "length" = 80,"gridSize" = grid_size_base, "curvature" = 0, "rightWidth" = W0/2, "leftWidth" = W0/2 ] ),
table([ "length" = evalf(Pi*75),"gridSize" = grid_size_base, "initialCurvature" = -1/75.,"finalCurvature" = 1/50.,
"rightWidth" = W0/2, "leftWidth" = W0/2 ] ),
table([ "length" = 90,"gridSize" = grid_size_base, "curvature" = 0, "rightWidth" = W0/2, "leftWidth" = W0/2 ] ),
table([ "length" = 10,"gridSize" = 0.1, "curvature" = 0, "rightWidth" = W0/2, "leftWidth" = W0/2 ] )
] ) ]:
The, we define the qvars
, i.e. the list of quantities that are fixed
functions of the independent variable \(s\) (the curvilinear abscissa).
The names on the RHS are internal to the Road2D
class and must not be
changed, but are remapped to the names in LHS. For instance,
Curv(s) = isoCurvature(s)
will map the curvature of the road to the
function name \(Curv(s)\) that we use to indicate the curvature in our
model equations (14), (15).
qvars := [
Curv(s) = isoCurvature(s),
leftWidth(s) = leftWidth(s),
rightWidth(s) = rightWidth(s),
xLane(s) = isoX(s),
yLane(s) = isoY(s),
theta(s) = isoAngle(s)
]:
Finally, we set the road object as follow:
mapUserFunctionToObject(
qvars,
"*pRoad", # is class tipo pointer
"Mechatronix#Road2D", # c (deve essere registrata)
road_data_init
);
Now, all the declared qvars
will be evaluated from the user-defined
road. For istance, the functions rightWidth
and leftWidth
can be
used to set the road limit constraints on the lateral distance of the
car as:
# Right road border
addUnilateralConstraint(
n(zeta)-vehHalfWidth >= -rightWidth(zeta),
roadRightLateralBoundaries,
epsilon = 0.001,
tolerance = 0.1,
scale = pen_scale
);
# Left road border
addUnilateralConstraint(
n(zeta)+vehHalfWidth <= leftWidth(zeta),
roadLeftLateralBoundaries,
epsilon = 0.001,
tolerance = 0.1,
scale = pen_scale
);
In the Figure shows the curvature we can see the curvature profile of the user-defined road. We can the segments with constant curvature, and the curvature of the clothoid segment, which by definition is linear.
Curvature of the user-defined road centerline.
After solving the minimum-time OCP we obtain the optimal trajectory for the vehicle of Figure shows the Optimal trajectory of the vehicle., plotted wiht the right and left border of the user-defined road; also, the car width at the center of mass is reported in the figure.
The optimal longitudinal and lateral velocity profiles of the vehicles are shown in the following figure:
In the Maple sheet the reader can study the plots of the optimal vehicle states and other interesting post-processing quantities related to the vehicle dynamics.
Single-Track Vehicle Model with Trajectory Class
Note
You can download this example as a Maple sheet:
03-SingleTrack_GivenTrajectory.zip
.
In this example we solve the minimum-time problem (or free-time problem)
while constraining the vehicle devation from a given a reference
trajectory. As in the previous example, the vehicle is a Single-Track
model with tyre ellipse of adherence. The vehicle maximum power is
constrained. The reference trajectory is given and functions are mapped
to methods of the Mechatronics library C++ Trajectory
class.
Again, the problem is formulated in curvilinear coordinates. This time
the reference trajectory is provided using an external file. The text
file trajectory_Data.txt
contains a look up table of values of the
reference line curvature as a function of the abscissa. The external
file trajectory_data.rb
reads and parse the trajectory data from the
text file, and create the mesh for the problem (we remind that the
abscissa will be the independent variable):
mesh_step = 0.1
mechatronix do |data|
# User defined classes initialization
# Read tabulated file data
# p "Start reading data from file"
pars, table = Utils::read_from_table(File.expand_path('../trajectory_data.txt', __FILE__))
puts table["abscissa"].size
# p "Data read correctly and trajectory built"
len = table["abscissa"][-1]-table["abscissa"][0]
puts "s0 = #{table["abscissa"][0]}, s1 = #{table["abscissa"][-1]}, len = #{len}"
npts = (len/mesh_step).round(0)
puts " mesh: number of points = #{npts}, mesh step = #{mesh_step} "
data.Trajectory =
{ :x0 => 0.0,
:y0 => 0.0,
:theta0 => 0.0,
:abscissa_step => mesh_step,
:mesh => {:segments=>[{:length=>1,:n=>npts},]},
:abscissa => table["abscissa"],
:curvature => table["curvature"],
}
end
The user can exploit the ruby
code to load any data or create a custom
mesh, but the structure data.Trajectory
must be returned. The XOptima library will create a list of clothoids from the provided
abscissa and curvature profiles in order to create the reference
trajectory.
In the Maple sheet we create a list of qvars
as in the previous
example:
qvars := [ Curv(s) = curvature(s),
xLane(s) = xTrajectory(s),
yLane(s) = yTrajectory(s),
theta(s) = heading(s) ]:
Then we setup the Trajectory
class:
mapUserFunctionToObject(
qvars,
"*pTrajectory", # istanza class tipo pointer
"Mechatronix#Path2D", # c (deve essere registrata)
"../../model/trajectory_data.rb"
);
Notice that the path to trajectory_data.rb
is provided to the command.
Now, we constraint the vehicle to remain inside a corridor around the
reference trajectory by setting a bound constraint on the lateral
position:
# Right road boarder
addUnilateralConstraint(
n(zeta) >= -n_max,
roadRightLateralBoundaries,
epsilon = epsi0,
tolerance = 0.1, #tolerance is specified as abs value
scale = pen_scale
);
# Left road boarder
addUnilateralConstraint(
n(zeta) <= n_max,
roadLeftLateralBoundaries,
epsilon = epsi0,
tolerance = 0.1, #tolerance is specified as abs value
scale = pen_scale
);
The curvature of the user-defined trajectory is shown in the following figure:
After solving the problem, we obtain the following optimal trajectory for the vehicle:
Optimal trajectory of the vehicle.
The lateral position error with respect to reference trajectory is the following:
Notice that, by reducing the value of the parameter n_max
in the
lateral distance constraint, we can enforce the vehicle to follow the
reference trajectory more closely.