MATLAB Examples

# TRUCK Truck simulation (v1.0)

Handle object that simulates a truck with a cabin and a truck.
t = TRUCK
Initiates truck with random position and orientation.
t = TRUCK(cabinRearCenter)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y] and random orientation.
t = TRUCK(cabinRearCenter, cabinOrientation)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y] and orientation cabinOrientation value in
degrees.
t = TRUCK(cabinRearCenter, cabinOrientation, cabinSteeringAngle)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y], orientation cabinOrientation value in
degrees and steering angle of its front wheels cabinSteeringAngle
value in degrees.
t = TRUCK(cabinRearCenter, cabinOrientation, cabinSteeringAngle,
trailerOrientation)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y], orientation cabinOrientation value in
degrees, steering angle of its front wheels cabinSteeringAngle value
in degrees and specific trailer orientation trailerOrientation value
in degrees.
t = TRUCK(cabinRearCenter, cabinOrientation, cabinSteeringAngle,
trailerOrientation, trailerLength)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y], orientation cabinOrientation value in
degrees, steering angle of its front wheels cabinSteeringAngle value
in degrees and specific trailer orientation trailerOrientation value
in degrees and length trailerLength.
t = TRUCK(cabinRearCenter, cabinOrientation, cabinSteeringAngle,
trailerOrientation, trailerLength, trailerWidth)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y], orientation cabinOrientation value in
degrees, steering angle of its front wheels cabinSteeringAngle value
in degrees and specific trailer orientation trailerOrientation value
in degrees, length trailerLength and width trailerWidth.
t = TRUCK(cabinRearCenter, cabinOrientation, cabinSteeringAngle,
trailerOrientation, trailerLength, trailerWidth, connectionLength)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y], orientation cabinOrientation value in
degrees, steering angle of its front wheels cabinSteeringAngle value
in degrees and specific trailer orientation trailerOrientation value
in degrees, length trailerLength and width trailerWidth and specific
length of connection connectionLength between cabin and truck.
t = TRUCK(cabinRearCenter, cabinOrientation, cabinSteeringAngle,
trailerOrientation, trailerLength, trailerWidth, connectionLength,
cabinSize)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y], orientation cabinOrientation value in
degrees, steering angle of its front wheels cabinSteeringAngle value
in degrees and specific trailer orientation trailerOrientation value
in degrees, length trailerLength and width trailerWidth and specific
length of connection connectionLength between cabin and truck and the
size of the squared cabin.
t = TRUCK(cabinRearCenter, cabinOrientation, cabinSteeringAngle,
trailerOrientation, trailerLength, trailerWidth, connectionLength,
cabinSize, wheelsDistance)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y], orientation cabinOrientation value in
degrees, steering angle of its front wheels cabinSteeringAngle value
in degrees and specific trailer orientation trailerOrientation value
in degrees, length trailerLength and width trailerWidth and specific
length of connection connectionLength between cabin and truck, the
size of the squared cabin and the distance between the wheels and the
closest edges of the vehicle.
t = TRUCK(cabinRearCenter, cabinOrientation, cabinSteeringAngle,
trailerOrientation, trailerLength, trailerWidth, connectionLength,
cabinSize, wheelsDistance, wheelsLength)
Initiates truck with specific cabin rear center position vector
cabinRearCenter = [x,y], orientation cabinOrientation value in
degrees, steering angle of its front wheels cabinSteeringAngle value
in degrees and specific trailer orientation trailerOrientation value
in degrees, length trailerLength and width trailerWidth and specific
length of connection connectionLength between cabin and truck, the
size of the squared cabin, the distance between the wheels and the
closest edges of the vehicle and the length of the wheels.
Any input arguments can be ignored setting it to '' while calling the
function.
t = t.randomInit
Specifies a random position and orientation to the truck.
[t_span, states] = t.move
Returns all states of the truck on a calculation of the moves the
truck to the actual direction. The calculations of this movement is
done within an infinitesimal time. The last movement defines the
actual states of the truck.
[t_span, states] = t.move(cabinSteeringAngleSpeed)
Returns all states of the truck on a calculation of the moves the
truck to the actual direction with specific speed of steering angle
of the front wheels of the cabin cabinSteeringAngleSpeed. The
calculations of this movement is done within an infinitesimal time.
The last movement defines the actual states of the truck.
[t_span, states] = t.move(cabinSteeringAngleSpeed,
cabinRearWheelsAcc)
Returns all states of the truck on a calculation of the moves the
truck to the actual direction with specific speed of steering angle
of the front wheels of the cabin cabinSteeringAngleSpeed and specific
acceleration of its rear wheels cabinRearWheelsAcc. The calculations
of this movement is done within an infinitesimal time.
The last movement defines the actual states of the truck.
[t_span, states] = t.move(cabinSteeringAngleSpeed,
cabinRearWheelsAcc, t_span)
Returns all states of the truck on a calculation of the moves the
truck to the actual direction with specific speed of steering angle
of the front wheels of the cabin cabinSteeringAngleSpeed and specific
acceleration of its rear wheels cabinRearWheelsAcc. The calculations
of this movement is done within each specific time inside vector
t_span.
The last movement defines the actual states of the truck.
The states is a vector defined as follows:
states = [cabinSteeringAngle;   ...
cabinRearWheelsSpeed, ...
cabinRearCenter;      ...
cabinOrientation;     ...
trailerOrientation]
fig = t.plot(fig, lineSpec, fillObj, holdFig)
Plots the truck on specific figure number or handle fig, line
specifications lineSpec, filling or not the object specified by
fillObj and holding or not the figure for next plot specified by
holdFig. All the options defined is saved and is used on next plot if
any of these options is not definied.
The fig option can be set as 'next' to remove last ploted truck of
the figure while holding it. This can be done to keep all objects
from figure when it is desirable to plot a new truck state.
Various line types, plot symbols and colors of lineSpec is defined as
plot bult-in functin and it is defined as a character string made
from one element from any or all the following 3 columns:
b     blue          .     point              -     solid
g     green         o     circle             :     dotted
r     red           x     x-mark             -.    dashdot
c     cyan          +     plus               --    dashed
m     magenta       *     star             (none)  no line
y     yellow        s     square
k     black         d     diamond
w     white         v     triangle (down)
^     triangle (up)
<     triangle (left)
>     triangle (right)
p     pentagram
h     hexagram
Filling object option may be defined by fillObj as 'filled'. Anything
else written that is different from this will be ignored.
Holding plot figure option for next plot may be defined by holdFig as
'hold'. Anything else written that is different from this will be
ignored.
Any input arguments can be ignored setting it to '' while calling the
function.
Example 1:
Creates one filled truck with cabin center position at [x,y] =
[50,50], orientation of 45° with relation to the global axes,
steering angle of its front wheels of -30° and orientation of 15° of
the trailer with relation to the global axes.
After that, reinitiate it three more times at a random position and
orientation (cabin front wheel steering angle will be zero) and plot
it again with red lines and not filled. The previous plot is holded.
t = truck([50,50], 45);
t.cabinSteeringAngle = -30;
t.trailerOrientation = 15;
t.plot(1,'','fill','hold');
t.randomInit;
t.plot('','r','');
for i = 1:2
t.randomInit;
t.plot;
end
Example 2:
Creates one non filled truck with random position and orientation but
steering angle of front wheels of the cabin of 0°.
After that, plot it and wait for the user to input keyboard arrows to
control the truck and calculates the next movement for an
infinitesimal time and replot it, removing last truck ploted. (the
previous plot is holded just to keep other possible objects in
figure), while the user does not press ESC key.
The warning messages is supressed to maintain user interface focused.
t = truck;
t.supressWarnings = 1;
h = t.plot;
while ishandle(h) && ~strcmp(t.lastPressedKey, 'escape')
t.move;
h = t.plot('next');
pause(.01);
end
%   Created by Fernando Freitas Alves
%   E-mail: fernando.freitas.alves@gmail.com

classdef truck < handle
properties (SetAccess = private)
frontCabinWheelsCenter     = [];             % Center coordinates [x y] of the front wheels of the cabin
connectionStart            = [];             % Start coordinates [x y] of the connection between cabin and trailer
trailerRearCenter          = [];             % Center coordinates [x y] of the rear of the trailer
lastPressedKey             = [];             % Last pressed key of keyboard in figure during plot
end
properties
cabinRearCenter            = [];             % Center coordinates [x y] of the rear of the cabin
cabinSteeringAngle         =  0;             % Angle of steering of the front wheels of the cabin
cabinOrientation           =  0;             % Orientation of the cabin in degrees
trailerOrientation         =  0;             % Orientation of the trailer in degrees
trailerLength              = 10;             % Length of the trailer
trailerWidth               =  5;             % Widht of the trailer
connectionLength           =  2.5;           % Length of connection between trailer and cab
cabinSize                  =  5;             % Size of the square cabin
wheelsDistance             =  0.1;           % Distance between the wheels and the edge of the vehicle
wheelsLength               =  0.3;           % Length of the wheels
cabinSteeringAngleSpeed    =  0;             % Speed of the angle of steering of the cabin
defCabinSteeringAngleSpeed =  5e3;           % Default speed of the angle of steering of the cabin
cabinRearWheelsSpeed       =  0;             % Speed of the rear wheels of the cabin
cabinRearWheelsAcc         =  0;             % Acceleration of the rear wheels of the cabin
defCabinRearWheelsAcc      =  5e4;           % Default acceleration of the rear wheels of the cabin
maxSteeringAngle           = 80;             % Maximum steering angle of the front wheels of the cabin
maxTrailerOrientation      = 90;             % Maximum trailer orientation with relation to the angle of the cabin
frictionFactor             =  2e2;           % Friction factor that limits the maximum velocity of the truck and breaks it when motor acceleration is zero.
supressWarnings            =  0;             % Supress warnings
end
properties (Access = private)
defDt                      =  1e-2;          % Default infinitesimal time
defT_span                  =  0:.001:.002;   % Default time span for dynamic calculation
defAxisLimits              = [0 100 0 100];  % Default axis limits [xmin xmax ymin ymax]
defLineSpec                = 'b';            % Default line specifications for plot
lastPlot                   = [];             % Last plot objects handles
lastFig                    = [];             % Last figure handle for plot
lastLineSpec               = [];             % Last line specifications for plot
lastFillObj                = [];             % Last fill option for plot
lastHoldFig                = [];             % Last hold option for plot
end
methods
function obj = truck(cabinRearCenter, cabinOrientation, ...
cabinSteeringAngle, trailerOrientation, ...
trailerLength, trailerWidth, ...
connectionLength, cabinSize, ...
wheelsDistance, wheelsLength)
% Initialize non defined arguments with defaut values
if nargin == 0
obj.randomInit;
else
if nargin >= 1
obj.cabinRearCenter = cabinRearCenter;
end
if nargin >= 2
obj.cabinOrientation = cabinOrientation;
end
if nargin >= 3
obj.cabinSteeringAngle = cabinSteeringAngle;
end
if nargin >= 4
obj.trailerOrientation = trailerOrientation;
end
if nargin >= 5
obj.trailerLength = trailerLength;
end
if nargin >= 6
obj.trailerWidth = trailerWidth;
end
if nargin >= 7
obj.connectionLength = connectionLength;
end
if nargin >= 8
obj.cabinSize = cabinSize;
end
if nargin >= 9
obj.wheelsDistance = wheelsDistance;
end
if nargin >= 10
obj.wheelsLength = wheelsLength;
end
end
end
function obj = randomInit(obj)
% Initiate the truck on a random position and orientation
maxLength = obj.trailerLength + ...
obj.trailerWidth  + ...
obj.connectionLength;
obj.cabinRearCenter    = obj.randomNumberBetween(maxLength, 100-maxLength, 2)';
obj.cabinSteeringAngle = 0;
obj.cabinOrientation   = obj.randomNumberBetween( 0, 360);
obj.trailerOrientation = obj.randomNumberBetween(-1,   1) * obj.maxTrailerOrientation + obj.cabinOrientation;
end
function obj = set.cabinRearCenter(obj,value)
if isequal(size(value),[1 2]) && ...
isnumeric(value) && ...
isreal(value)
obj.cabinRearCenter = value;
elseif isequal(size(value),[2 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.cabinRearCenter = value';
else
error('Center value of the rear of the cabin must be a real array with x and y arguments');
end
end
function value = get.frontCabinWheelsCenter(obj)
value =   obj.cabinRearCenter ...
+ obj.cabinSize * (1 - (obj.wheelsDistance + obj.wheelsLength/2)) ...
* [cosd(obj.cabinOrientation)  ...
sind(obj.cabinOrientation)];
wheelCenterDist = (obj.cabinSize * (0.5 - obj.wheelsDistance)) ...
* [cosd(90 + obj.cabinOrientation)  ...
sind(90 + obj.cabinOrientation)];
value = repmat(value, [2 1]) + [1; -1] * wheelCenterDist;
obj.frontCabinWheelsCenter = value;
end
function value = get.connectionStart(obj)
value =   obj.cabinRearCenter ...
- obj.connectionLength * [cosd(obj.trailerOrientation) ...
sind(obj.trailerOrientation)];
obj.connectionStart = value;
end
function value = get.trailerRearCenter(obj)
value =   obj.cabinRearCenter ...
- (obj.trailerLength   + obj.connectionLength) * [cosd(obj.trailerOrientation) ...
sind(obj.trailerOrientation)];
obj.trailerRearCenter = value;
end
function obj = set.cabinOrientation(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.cabinOrientation = value;
else
error('Orientation value of the cabin must be a real scalar');
end
end
function obj = set.cabinSteeringAngle(obj,value)
msg = ['Steering angle value of the front wheels of the cabin must be a real that do not exceeds the maximum steering of ' num2str(obj.maxSteeringAngle) '°'];
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
if abs(value) <= obj.maxSteeringAngle
obj.cabinSteeringAngle = value;
else
if ~obj.supressWarnings
warning(msg);
end
obj.cabinSteeringAngle = obj.maxSteeringAngle ...
* sign(value);
end
else
error(msg);
end
end
function obj = set.trailerOrientation(obj,value)
msg = ['Orientation value of the trailer must be a real that do not exceeds the maximum steering of ' num2str(obj.maxTrailerOrientation) '° with relation to the angle of the cabin'];
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
if abs(value - obj.cabinOrientation) <= obj.maxTrailerOrientation
obj.trailerOrientation = value;
else
if ~obj.supressWarnings
warning(msg);
end
obj.trailerOrientation = obj.maxTrailerOrientation ...
* sign(value - obj.cabinOrientation) ...
+ obj.cabinOrientation;
end
else
error(msg);
end
end
function obj = set.trailerLength(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value) && ...
value > 0
obj.trailerLength = value;
else
error('Length value of the trailer must be a real positive scalar');
end
end
function obj = set.trailerWidth(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value) && ...
value > 0
obj.trailerWidth = value;
else
error('Width value of the trailer must be a real positive scalar');
end
end
function obj = set.connectionLength(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value) && ...
value > 0
obj.connectionLength = value;
else
error('Length value of connection between cabin and trailer must be a real positive scalar');
end
end
function obj = set.cabinSize(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value) && ...
value > 0
obj.cabinSize = value;
else
error('Cabin size value must be a real positive scalar');
end
end
function obj = set.wheelsDistance(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value) && ...
value > 0 && value < 0.5
obj.wheelsDistance = value;
else
error('Wheels distance size value must be a real positive scalar less than 0.5');
end
end
function obj = set.wheelsLength(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value) && ...
value > 0
obj.wheelsLength = value;
else
error('Wheels length value must be a real scalar');
end
end
function obj = set.cabinSteeringAngleSpeed(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.cabinSteeringAngleSpeed = value;
else
error('Speed value of the angle of steering of the cabin must be a real scalar');
end
end
function obj = set.defCabinSteeringAngleSpeed(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.defCabinSteeringAngleSpeed = value;
else
error('Default value of speed of the angle of steering of the cabin must be a real scalar');
end
end
function obj = set.cabinRearWheelsSpeed(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.cabinRearWheelsSpeed = value;
else
error('Speed value of the rear wheels of the cabin must be a real scalar');
end
end
function obj = set.cabinRearWheelsAcc(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.cabinRearWheelsAcc = value;
else
error('Acceleration value of the rear wheels of the cabin must be a real scalar');
end
end
function obj = set.defCabinRearWheelsAcc(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.defCabinRearWheelsAcc = value;
else
error('Default value of acceleration of the rear wheels of the cabin must be a real scalar');
end
end
function obj = set.maxSteeringAngle(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.maxSteeringAngle = value;
else
error('Maximum value of steering angle of the front wheels of the cabin must be a real scalar');
end
end
function obj = set.maxTrailerOrientation(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.maxTrailerOrientation = value;
else
error('Maximum value of trailer orientation must be a real scalar');
end
end
function obj = set.frictionFactor(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
isreal(value)
obj.frictionFactor = value;
else
error('Friction factor value must be a real scalar');
end
end
function obj = set.supressWarnings(obj,value)
if isequal(size(value),[1 1]) && ...
isnumeric(value) && ...
(value == 1 || value == 0)
obj.supressWarnings = value;
else
error('Supress warnings must be a numeric boolean value (1 or 0)');
end
end
function [t_span, states] = move(obj, cabinSteeringAngleSpeed, cabinRearWheelsAcc, t_span)
% Moves the truck by applying a speed to the rear wheels of the
% cabin
if nargin < 2
cabinSteeringAngleSpeed = obj.cabinSteeringAngleSpeed;
else
obj.cabinSteeringAngleSpeed = cabinSteeringAngleSpeed;
end
if nargin < 3
cabinRearWheelsAcc = obj.cabinRearWheelsAcc;
else
obj.cabinRearWheelsAcc = cabinRearWheelsAcc;
end
if nargin < 4
t_span = obj.defT_span;
end
[t_span,states] = ode45(@(t, y) obj.moveODE(t, y, cabinSteeringAngleSpeed, cabinRearWheelsAcc), ...
t_span, ...
[obj.cabinSteeringAngle  ; ...
obj.cabinRearWheelsSpeed; ...
obj.cabinRearCenter'    ; ...
obj.cabinOrientation    ; ...
obj.trailerOrientation]);
end
function fig = plot(obj, fig, lineSpec, fillObj, holdFig)
% Plot the truck on a figure
if nargin < 2 || ...
~isnumeric(fig) && ~isa(fig,'handle') || ...
fig == 0
if nargin >= 2 && strcmpi(fig,'new') || ...
isempty(obj.lastFig)
fig = figure('KeyPressFcn',   @obj.figureKeyPress, ...
'KeyReleaseFcn', @obj.figureKeyRelease);
elseif nargin >= 2 && strcmpi(fig,'next') && ...
~isempty(obj.lastFig)
delete(obj.lastPlot);
fig = figure(obj.lastFig);
else
fig = figure(obj.lastFig);
end
else
if isnumeric(fig)
fig = floor(fig);
end
fig = figure(fig);
end
if nargin < 3
if isempty(obj.lastLineSpec)
lineSpec = obj.defLineSpec;
else
lineSpec = obj.lastLineSpec;
end
end
if nargin < 4
if ~isempty(obj.lastFillObj)
fillObj = obj.lastFillObj;
else
fillObj = '';
end
end
if nargin >= 5 && strcmpi(holdFig, 'hold') || ...
strcmpi(obj.lastHoldFig, 'hold')
hold on
holdFig = 'hold';
else
holdFig = '';
end
global axisLimits
if isempty(axisLimits)
axisLimits = obj.defAxisLimits;
end

% Assign points and lines of the truck
% Points of cabin (pc) and trailer (pt)  as [xmin xmax ymin ymax]
% and  connection (pn) and wheels  (p*w) as [xi   xf   yi   yf]
pc  = [  0                       obj.cabinSize                           -obj.cabinSize/2             obj.cabinSize/2];
pt  = [  0                       obj.trailerLength                       -obj.trailerWidth/2          obj.trailerWidth/2];
pn  = [  0                       obj.connectionLength                     0                           0];
pcw = [  obj.wheelsDistance      obj.wheelsDistance+obj.wheelsLength      0.5-obj.wheelsDistance      0.5-obj.wheelsDistance;
obj.wheelsDistance      obj.wheelsDistance+obj.wheelsLength    -(0.5-obj.wheelsDistance)   -(0.5-obj.wheelsDistance);
1-obj.wheelsDistance   1-(obj.wheelsDistance+obj.wheelsLength)     0.5-obj.wheelsDistance      0.5-obj.wheelsDistance;
1-obj.wheelsDistance   1-(obj.wheelsDistance+obj.wheelsLength)   -(0.5-obj.wheelsDistance)   -(0.5-obj.wheelsDistance)] ...
* obj.cabinSize;
ptw = [  obj.wheelsDistance      obj.wheelsDistance+obj.wheelsLength      0.5-obj.wheelsDistance      0.5-obj.wheelsDistance;
obj.wheelsDistance      obj.wheelsDistance+obj.wheelsLength    -(0.5-obj.wheelsDistance)   -(0.5-obj.wheelsDistance);
1-obj.wheelsDistance   1-obj.wheelsLength                          0.5-obj.wheelsDistance      0.5-obj.wheelsDistance;
1-obj.wheelsDistance   1-obj.wheelsLength                        -(0.5-obj.wheelsDistance)   -(0.5-obj.wheelsDistance)] ...
* [obj.trailerLength   0               zeros(1,2); ...
0                   obj.cabinSize   zeros(1,2); ...
zeros(2)                            eye(2)*obj.trailerWidth];
ptw = ptw(1:2,:);
ptw(:,2) = ptw(:,1) + pcw(1,2) - pcw(1,1);

% Translates cabin and trailer to each center of its rear and
% the connection to the front of trailer
pc  = pc  + repelem(obj.cabinRearCenter,   2);
pt  = pt  + repelem(obj.trailerRearCenter, 2);
pn  = pn  + repelem(obj.connectionStart,   2);
pcw = pcw + repmat(repelem(obj.cabinRearCenter,   2), [size(pcw,1) 1]);
ptw = ptw + repmat(repelem(obj.trailerRearCenter, 2), [size(ptw,1) 1]);

% Lines cell of the trailer {line number, [1:x, 2:y]}
lTrailer{1,1} = [pt(1) pt(1)];
lTrailer{1,2} = [pt(3) pt(4)];

lTrailer{2,1} = [pt(1) pt(2)];
lTrailer{2,2} = [pt(4) pt(4)];

lTrailer{3,1} = [pt(2) pt(2)];
lTrailer{3,2} = [pt(4) pt(3)];

lTrailer{4,1} = [pt(2) pt(1)];
lTrailer{4,2} = [pt(3) pt(3)];

% Lines cell of the cabin {line number, [1:x, 2:y]}
lCabin{1,1} = [pc(1) pc(1)];
lCabin{1,2} = [pc(3) pc(4)];

lCabin{2,1} = [pc(1) pc(2)];
lCabin{2,2} = [pc(4) pc(4)];

lCabin{3,1} = [pc(2) pc(2)];
lCabin{3,2} = [pc(4) pc(3)];

lCabin{4,1} = [pc(2) pc(1)];
lCabin{4,2} = [pc(3) pc(3)];

% Lines cell of the connection {line number, [1:x, 2:y]}
lConnection{1,1} = pn(1:2);
lConnection{1,2} = pn(3:4);

% Lines cell of the cabin's wheels {line number, [1:x, 2:y]}
nCWheels = size(pcw,1);
lCWheels = cell(nCWheels,2);
for w = 1:nCWheels
lCWheels{w,1} = pcw(w,1:2);
lCWheels{w,2} = pcw(w,3:4);
end

% Lines cell of the trailer's wheels {line number, [1:x, 2:y]}
nTWheels = size(ptw,1);
lTWheels = cell(nTWheels,2);
for w = 1:nTWheels
lTWheels{w,1} = ptw(w,1:2);
lTWheels{w,2} = ptw(w,3:4);
end

% Plots and rotates obj
objPlot = zeros(1, 1 + nCWheels + nTWheels);
if strcmpi(fillObj, 'fill')
lh = fill(cell2mat(lCabin(:,1)'), ...
cell2mat(lCabin(:,2)'), ...
lineSpec);
hold on
objPlot(1) = lh;
for w = 1:nCWheels
objPlot(1+w) = plot(cell2mat(lCWheels(w,1)'), ...
cell2mat(lCWheels(w,2)'), ...
lineSpec, ...
'Color', lh.EdgeColor);
end
for w = 1:nTWheels
objPlot(1+nCWheels+w) = plot(cell2mat(lTWheels(w,1)'), ...
cell2mat(lTWheels(w,2)'), ...
lineSpec, ...
'Color', lh.EdgeColor);
end
objPlot = [objPlot fill(cell2mat(lTrailer(:,1)'), ...
cell2mat(lTrailer(:,2)'), ...
lineSpec, ...
'EdgeColor', lh.EdgeColor, ...
'FaceColor', lh.FaceColor) ...
plot(cell2mat(lConnection(:,1)'), ...
cell2mat(lConnection(:,2)'), ...
lineSpec, ...
'Color', lh.EdgeColor)];
else
lh = plot(cell2mat(lCabin(:,1)'), ...
cell2mat(lCabin(:,2)'), ...
lineSpec);
hold on
objPlot(1) = lh;
for w = 1:nCWheels
objPlot(1+w) = plot(cell2mat(lCWheels(w,1)'), ...
cell2mat(lCWheels(w,2)'), ...
lineSpec, ...
'Color', lh.Color);
end
for w = 1:nTWheels
objPlot(1+nCWheels+w) = plot(cell2mat(lTWheels(w,1)'), ...
cell2mat(lTWheels(w,2)'), ...
lineSpec, ...
'Color', lh.Color);
end
objPlot = [objPlot plot(cell2mat(lTrailer(:,1)'), ...
cell2mat(lTrailer(:,2)'), ...
lineSpec, ...
'Color', lh.Color) ...
plot(cell2mat(lConnection(:,1)'), ...
cell2mat(lConnection(:,2)'), ...
lineSpec, ...
'Color', lh.Color)];
end
rotate(objPlot(1:1+nCWheels), [0 0 1], ...
obj.cabinOrientation, ...
[obj.cabinRearCenter 0]);
rotate(objPlot(2+nCWheels:2+nCWheels+nTWheels), [0 0 1], ...
obj.trailerOrientation, ...
[obj.trailerRearCenter 0]);
rotate(objPlot(3+nCWheels+nTWheels), [0 0 1], ...
obj.trailerOrientation, ...
[obj.connectionStart 0]);
fcwc = obj.frontCabinWheelsCenter;
rotate(objPlot(4), [0 0 1], ...
obj.cabinSteeringAngle, ...
[fcwc(1,:) 0]);
rotate(objPlot(5), [0 0 1], ...
obj.cabinSteeringAngle, ...
[fcwc(2,:) 0]);
axis equal
axis(axisLimits);
hold off

% Holds last assignments
obj.lastPlot     = [obj.lastPlot objPlot];
obj.lastFig      = fig.Number;
obj.lastLineSpec = lineSpec;
obj.lastFillObj  = fillObj;
obj.lastHoldFig  = holdFig;
end
end
methods (Access = private)
function n = randomNumberBetween(~, min, max, size)
% Generates a random number vector between min and max with
% specific size.
if nargin < 4
size = 1;
end
n = (max - min) * rand(size,1) + min;
end
function dy = moveODE(obj, ~, y, cabinSteeringAngleSpeed, cabinRearWheelsAcc)
% Defines the system of ordinaries diferential equations of the
% state variables of the truck kinematics.
obj.cabinSteeringAngle   =  y(1);
obj.cabinRearWheelsSpeed =  y(2);
obj.cabinRearCenter      = [y(3) y(4)];
obj.cabinOrientation     =  y(5);
obj.trailerOrientation   =  y(6);

dCabinSteeringAngle   = cabinSteeringAngleSpeed;
dCabinRearWheelsSpeed = cabinRearWheelsAcc - obj.frictionFactor ...
* obj.cabinRearWheelsSpeed;
dCabinRearCenter      = obj.cabinRearWheelsSpeed * [cosd(obj.cabinOrientation) ...
sind(obj.cabinOrientation)];
dCabinOrientation     = obj.cabinRearWheelsSpeed *  tand(obj.cabinSteeringAngle)    ...
/  obj.cabinSize ...
*  180 / pi;
dTrailerOrientation   = obj.cabinRearWheelsSpeed *  sind(obj.cabinOrientation - obj.trailerOrientation) ...
/  obj.trailerLength ...
*  180 / pi;
dy = [dCabinSteeringAngle  ; ...
dCabinRearWheelsSpeed; ...
dCabinRearCenter'    ; ...
dCabinOrientation    ; ...
dTrailerOrientation];
end
function key = figureKeyPress(obj, ~, e)
% Gets the actual pressed key of the keyboard inside figure plot.
key = e.Key;
switch key
case 'leftarrow'
obj.cabinSteeringAngleSpeed = +obj.defCabinSteeringAngleSpeed;
case 'rightarrow'
obj.cabinSteeringAngleSpeed = -obj.defCabinSteeringAngleSpeed;
case 'uparrow'
obj.cabinRearWheelsAcc = +obj.defCabinRearWheelsAcc;
case 'downarrow'
obj.cabinRearWheelsAcc = -obj.defCabinRearWheelsAcc;
end
obj.lastPressedKey = key;
end
function figureKeyRelease(obj, ~, e)
% Stops acelerating speeds.
switch e.Key
case 'leftarrow'
obj.cabinSteeringAngleSpeed = 0;
case 'rightarrow'
obj.cabinSteeringAngleSpeed = 0;
case 'uparrow'
obj.cabinRearWheelsAcc = 0;
case 'downarrow'
obj.cabinRearWheelsAcc = 0;
end
end
end
methods (Access = private, Hidden = true)
function move_manual(obj, cabinSteeringAngleSpeed, cabinRearWheelsSpeed, dt)
% Calculates manually the system of ordinaries diferential
% equations of the state variables of the truck kinematics with a
% specific infinitesimal time dt.
if nargin < 2
cabinSteeringAngleSpeed = obj.cabinSteeringAngleSpeed;
else
obj.cabinSteeringAngleSpeed = cabinSteeringAngleSpeed;
end
if nargin < 3
cabinRearWheelsSpeed = obj.cabinRearWheelsSpeed;
else
obj.cabinRearWheelsSpeed = cabinRearWheelsSpeed;
end
if nargin < 4
dt = obj.defDt;
end
obj.cabinSteeringAngle = obj.cabinSteeringAngle ...
+ cabinSteeringAngleSpeed * dt;
obj.cabinRearCenter    = obj.cabinRearCenter ...
+ cabinRearWheelsSpeed * dt ...
* [cosd(obj.cabinOrientation) ...
sind(obj.cabinOrientation)];
obj.cabinOrientation   = obj.cabinOrientation ...
+ cabinRearWheelsSpeed * dt ...
* tand(obj.cabinSteeringAngle) ...
/  obj.cabinSize ...
* 180 / pi;
obj.trailerOrientation = obj.trailerOrientation ...
+ cabinRearWheelsSpeed * dt ...
* sind(obj.cabinOrientation - obj.trailerOrientation) ...
/ obj.trailerLength ...
* 180 / pi;
end
end
end