Application Center - Maplesoft

App Preview:

Mobile Robot

You can switch back to the summary page by clicking here.

Learn about Maple
Download Application


 

Image 

Mobile Robot
Simulation and Control
 

? Maplesoft, a division of Waterloo Maple Inc., 2008 

Given the model of a two wheel differential drive mobile robot, we would like to simulate its trajectory response to various inputs in both open and closed loop settings. The robot model has been derived in a separate application example worksheet titled Mobile Robot Modeling and Simulation . 

System Definition 

 

 

 

 

 

Robot System Model 

 

Simulations 

 

 

 

 

 

 

PlotPlot_2d 

The robot has two independent wheels, each connected to a motor. This way the robot can move forward, back, and turn.  

System Definition 

Define the Variables and the Parameters that describe the system. 

Parameters 

Name 

Value 

Units 

Robot Parameters 

Robot Chassis Radius (r_c

Embedded component 

Unit('m') 

Robot Chassis Mass (m_c

Embedded component 

Unit('kg') 

Robot Chassis Moment of Inertia (I_zz

Embedded component 

Unit(`*`('kg', `*`(`^`('m', 2)))) 

Wheel Parameters 

Wheel Radius (r_w

Embedded component 

Unit('m') 

Wheel Mass (m_w

Embedded component 

Unit('kg') 

Wheel Moment of Inertia (I_w

Embedded component 

Unit(`*`('kg', `*`(`^`('m', 2)))) 

Motor Parameters 

DC Motor Armature Resistance (Ra_m

Embedded component 

Unit('Omega') 

DC Motor Armature Inductance (La_m

Embedded component 

Unit('H') 

DC Motor Torque Constants (KMotor_m

Embedded component 

Unit(`/`(`*`('N', `*`('m')), `*`('A'))) 

DC Motor EMF Constants (Kemf_m

Embedded component 

Unit(`/`(`*`('N', `*`('m')), `*`('A'))) 

Button# Retrieve Parameters Defined

{I_w = 0.15625e-4, m_c = 5.0, m_w = 0.5e-1, r_c = .25, r_w = .15, I_zz = .15625, Kemf_m = .2, La_m = .5, Ra_m = 1.0, KMotor_m = .2}
{I_w = 0.15625e-4, m_c = 5.0, m_w = 0.5e-1, r_c = .25, r_w = .15, I_zz = .15625, Kemf_m = .2, La_m = .5, Ra_m = 1.0, KMotor_m = .2}

Variables 

 

Name 

Description 

Robot State 

x(t), y(t) 

Robot Position (x and y coordinates) 

theta(t) 

Robot Heading (counter clockwise from the x-axis when viewed from top) 

v(t) 

Robot Linear Velocity (w.r.t. Body Fixed Frame, positive going forward) 

w(t) 

Robot Angular Velocity (w.r.t. Body Fixed Frame, about vertical axis) 

Wheel Variables 

omega[L](t), omega[R](t) 

Wheel Angular Speed (left and right) 

tau[L](t), tau[R](t) 

Wheel Applied Torque (left and right) 

F[L](t), F[R](t) 

Wheel Traction Force (left and right) 

Motor Variables 

i[L](t), i[R](t) 

Motor Current (left and right) 

u[L](t), u[R](t) 

Motor Input Voltage (left and right) 

Robot System Model 

The model of the robot has been derived in the MobileRobotModel worksheet.  The overall system of equations is given as follows: 

Button# Overall System Model 

 

Equations for the linear acceleration in the x and y direction and the angular acceleration: 

LinAcc 

Vector[column](%id = 52583668) = Vector[column](%id = 52591836) (2.1)
 

Equations for the linear and angular velocities: 

LinAngVel 

Vector[column](%id = 52593200) = Vector[column](%id = 52593520) (2.2)
 

Equations for the angular velocities of the wheels: 

AngVelWh1 

diff(omega_R(t), t) = `+`(`/`(`*`(`/`(1, 2), `*`(`+`(`*`(4, `*`(tau_R(t), `*`(I_zz, `*`(`^`(r_w, 2))))), `*`(4, `*`(I_zz, `*`(`^`(r_w, 2), `*`(tau_L(t))))), `-`(`*`(`^`(r_c, 2), `*`(m_c, `*`(`^`(r_w, ...
diff(omega_R(t), t) = `+`(`/`(`*`(`/`(1, 2), `*`(`+`(`*`(4, `*`(tau_R(t), `*`(I_zz, `*`(`^`(r_w, 2))))), `*`(4, `*`(I_zz, `*`(`^`(r_w, 2), `*`(tau_L(t))))), `-`(`*`(`^`(r_c, 2), `*`(m_c, `*`(`^`(r_w, ...
diff(omega_R(t), t) = `+`(`/`(`*`(`/`(1, 2), `*`(`+`(`*`(4, `*`(tau_R(t), `*`(I_zz, `*`(`^`(r_w, 2))))), `*`(4, `*`(I_zz, `*`(`^`(r_w, 2), `*`(tau_L(t))))), `-`(`*`(`^`(r_c, 2), `*`(m_c, `*`(`^`(r_w, ...
diff(omega_R(t), t) = `+`(`/`(`*`(`/`(1, 2), `*`(`+`(`*`(4, `*`(tau_R(t), `*`(I_zz, `*`(`^`(r_w, 2))))), `*`(4, `*`(I_zz, `*`(`^`(r_w, 2), `*`(tau_L(t))))), `-`(`*`(`^`(r_c, 2), `*`(m_c, `*`(`^`(r_w, ...
(2.3)
 

AngVelWh2 

diff(omega_L(t), t) = `+`(`/`(`*`(`/`(1, 2), `*`(`+`(`-`(`*`(`^`(r_c, 2), `*`(tau_R(t), `*`(m_c, `*`(`^`(r_w, 2)))))), `*`(`^`(r_c, 2), `*`(m_c, `*`(`^`(r_w, 2), `*`(tau_L(t))))), `*`(4, `*`(`^`(r_c, ...
diff(omega_L(t), t) = `+`(`/`(`*`(`/`(1, 2), `*`(`+`(`-`(`*`(`^`(r_c, 2), `*`(tau_R(t), `*`(m_c, `*`(`^`(r_w, 2)))))), `*`(`^`(r_c, 2), `*`(m_c, `*`(`^`(r_w, 2), `*`(tau_L(t))))), `*`(4, `*`(`^`(r_c, ...
diff(omega_L(t), t) = `+`(`/`(`*`(`/`(1, 2), `*`(`+`(`-`(`*`(`^`(r_c, 2), `*`(tau_R(t), `*`(m_c, `*`(`^`(r_w, 2)))))), `*`(`^`(r_c, 2), `*`(m_c, `*`(`^`(r_w, 2), `*`(tau_L(t))))), `*`(4, `*`(`^`(r_c, ...
diff(omega_L(t), t) = `+`(`/`(`*`(`/`(1, 2), `*`(`+`(`-`(`*`(`^`(r_c, 2), `*`(tau_R(t), `*`(m_c, `*`(`^`(r_w, 2)))))), `*`(`^`(r_c, 2), `*`(m_c, `*`(`^`(r_w, 2), `*`(tau_L(t))))), `*`(4, `*`(`^`(r_c, ...
(2.4)
 

Equations for the wheel torques: 

WhTor 

Vector[column](%id = 52595072) = Vector[column](%id = 52595392) (2.5)
 

Equations for the motor currents: 

MotorCur 

Vector[column](%id = 52600644) = Vector[column](%id = 52604608) (2.6)
 

 

Simulation 

Open Loop Case 

Here, we specify the input voltage to each of the two motors and observe the system response (uncontrolled). 

System Input 

Button# Open Loop System Input 

The inputs to the combined system are the applied voltage to the motor. For the simulation, they are defined as piecewise continuous functions. 

LeftWheel 

u_L(t) = piecewise(`and`(`<`(0, t), `<`(t, 2)), .5, `and`(`<`(2, t), `<`(t, 4)), 0., `and`(`<`(4, t), `<`(t, 6)), .5, `and`(`<`(6, t), `<`(t, 8)), .25, `and`(`<`(8, t), `<`(t, 10)), .5, 0)
u_L(t) = piecewise(`and`(`<`(0, t), `<`(t, 2)), .5, `and`(`<`(2, t), `<`(t, 4)), 0., `and`(`<`(4, t), `<`(t, 6)), .5, `and`(`<`(6, t), `<`(t, 8)), .25, `and`(`<`(8, t), `<`(t, 10)), .5, 0)
(3.1.1.1)
 

 

MotorInputVoltage 

Plot_2d  
 

 

RightWheel 

u_R(t) = piecewise(`and`(`<`(0, t), `<`(t, 4)), .5, `and`(`<`(4, t), `<`(t, 8)), .25, 0)
u_R(t) = piecewise(`and`(`<`(0, t), `<`(t, 4)), .5, `and`(`<`(4, t), `<`(t, 8)), .25, 0)
(3.1.1.2)
 

 

System Initial Conditions 

Button# Open Loop Initial Conditions 

The robot is assumed to be at the origin at rest. The following initial conditions describe this state. 

Robot initial conditions 

RobotIC 

{v(0) = 0, w(0) = 0, x(0) = 0, y(0) = 0, theta(0) = 0, (D(x))(0) = 0, (D(y))(0) = 0, (D(theta))(0) = 0}
{v(0) = 0, w(0) = 0, x(0) = 0, y(0) = 0, theta(0) = 0, (D(x))(0) = 0, (D(y))(0) = 0, (D(theta))(0) = 0}
{v(0) = 0, w(0) = 0, x(0) = 0, y(0) = 0, theta(0) = 0, (D(x))(0) = 0, (D(y))(0) = 0, (D(theta))(0) = 0}
{v(0) = 0, w(0) = 0, x(0) = 0, y(0) = 0, theta(0) = 0, (D(x))(0) = 0, (D(y))(0) = 0, (D(theta))(0) = 0}
(3.1.2.1)
 

 

Wheel initial conditions 

WheelIC 

{omega_L(0) = 0., omega_R(0) = 0.}
{omega_L(0) = 0., omega_R(0) = 0.}
(3.1.2.2)
 

 

Motor initial conditions 

MotorIC 

{i_L(0) = 0., i_R(0) = 0.} (3.1.2.3)
 

 

System Response 

Button# Open Loop System Response 

 

Robot X and Y Position 

Robot Heading 

OpenLoopXYPos 

Plot_2d  
 

 

OpenLoopHeading 

Plot_2d  
 

 

Robot Chassis Linear and Angular Velocities 

Trajectory Animation 

OpenLoopLinAngVel 

Plot_2d  
 

 

OpenLoopTraj 

Plot  
 

 

 

 

Speed Control 

We want to implement a proportional-integral PI controllers to control the linear and angular speeds. The linear speed determines how fast the robot is moving forward, while the angular speed determines how fast the robot is turning. 

System Input 

Button# Speed Control System Input 

The following inputs are applied to the system. The robot will first turn (rotate), then start moving forward while rotating, and finally move forward without turning before coming to a stop. 

ForwardSpeed 

Plot_2d  
 

 

TurningSpeed 

Plot_2d  
 

 

Controller Definition 

We will use two independent PI controllers to control the forward (v(t)) and turning (w(t)) speed of the robot. 

The output of the PI controllers are the forward control input u[v](t) and the turning control input  

`:=`(eqnset_speed_PI, {u_v(t) = `+`(`*`(Kpv, `*`(error_v(t))), `*`(Kiv, `*`(i_error_v(t)))), u_w(t) = `+`(`*`(Kpw, `*`(error_w(t))), `*`(Kiw, `*`(i_error_w(t))))}); -1; u_v(t) = eval(u_v(t), eqnset_sp...
`:=`(eqnset_speed_PI, {u_v(t) = `+`(`*`(Kpv, `*`(error_v(t))), `*`(Kiv, `*`(i_error_v(t)))), u_w(t) = `+`(`*`(Kpw, `*`(error_w(t))), `*`(Kiw, `*`(i_error_w(t))))}); -1; u_v(t) = eval(u_v(t), eqnset_sp...
`:=`(eqnset_speed_PI, {u_v(t) = `+`(`*`(Kpv, `*`(error_v(t))), `*`(Kiv, `*`(i_error_v(t)))), u_w(t) = `+`(`*`(Kpw, `*`(error_w(t))), `*`(Kiw, `*`(i_error_w(t))))}); -1; u_v(t) = eval(u_v(t), eqnset_sp...
 

u_v(t) = `+`(`*`(Kpv, `*`(error_v(t))), `*`(Kiv, `*`(i_error_v(t)))) (3.2.2.1)
 

 

u_w(t) = eval(u_w(t), eqnset_speed_PI) 

u_w(t) = `+`(`*`(Kpw, `*`(error_w(t))), `*`(Kiw, `*`(i_error_w(t)))) (3.2.2.2)
 

 

 

where the error (and its integral) in v(t) and w(t) are defined as: 

 

`:=`(vw_error, {error_v(t) = `+`(v_ref(t), `-`(v(t))), error_w(t) = `+`(w_ref(t), `-`(w(t)))}); -1; `:=`(vw_i_error, {diff(i_error_v(t), t) = error_v(t), diff(i_error_w(t), t) = error_w(t)}); -1; erro...
`:=`(vw_error, {error_v(t) = `+`(v_ref(t), `-`(v(t))), error_w(t) = `+`(w_ref(t), `-`(w(t)))}); -1; `:=`(vw_i_error, {diff(i_error_v(t), t) = error_v(t), diff(i_error_w(t), t) = error_w(t)}); -1; erro...
`:=`(vw_error, {error_v(t) = `+`(v_ref(t), `-`(v(t))), error_w(t) = `+`(w_ref(t), `-`(w(t)))}); -1; `:=`(vw_i_error, {diff(i_error_v(t), t) = error_v(t), diff(i_error_w(t), t) = error_w(t)}); -1; erro...
 

error_v(t) = `+`(v_ref(t), `-`(v(t))) (3.2.2.3)
 

 

diff(i_error_v(t), t) = eval(diff(i_error_v(t), t), vw_i_error) 

diff(i_error_v(t), t) = error_v(t) (3.2.2.4)
 

error_w(t) = eval(error_w(t), vw_error) 

error_w(t) = `+`(w_ref(t), `-`(w(t))) (3.2.2.5)
 

diff(i_error_w(t), t) = eval(diff(i_error_w(t), t), vw_i_error) 

diff(i_error_w(t), t) = error_w(t) (3.2.2.6)
 

 

Parameter values for the Speed PI Controllers 

Gain 

Value 

Forward Speed Control 

K[P[v]] 

Embedded component 

K[I[v]] 

Embedded component 

Turning Speed Control 

K[P[w]] 

Embedded component 

K[I[w]] 

Embedded component 

Initial Conditions: 

 

`:=`(vwctl_IC, {u_L(0) = 0, u_R(0) = 0, i_error_v(0) = 0, i_error_w(0) = 0}); -1; vwctl_IC
`:=`(vwctl_IC, {u_L(0) = 0, u_R(0) = 0, i_error_v(0) = 0, i_error_w(0) = 0}); -1; vwctl_IC
`:=`(vwctl_IC, {u_L(0) = 0, u_R(0) = 0, i_error_v(0) = 0, i_error_w(0) = 0}); -1; vwctl_IC
 

{u_L(0) = 0, u_R(0) = 0, i_error_v(0) = 0, i_error_w(0) = 0}
{u_L(0) = 0, u_R(0) = 0, i_error_v(0) = 0, i_error_w(0) = 0}
(3.2.2.7)
 

 

u_L(t) = eval(u_L(t), eqnset_speed_motor_input_voltage)
u_L(t) = eval(u_L(t), eqnset_speed_motor_input_voltage)
 

u_L(t) = `+`(`-`(`*`(`/`(1, 2), `*`(u_w(t)))), `*`(`/`(1, 2), `*`(u_v(t)))) (3.2.2.10)
 

u_R(t) = eval(u_R(t), eqnset_speed_motor_input_voltage)
u_R(t) = eval(u_R(t), eqnset_speed_motor_input_voltage)
 

u_R(t) = `+`(`*`(`/`(1, 2), `*`(u_v(t))), `*`(`/`(1, 2), `*`(u_w(t)))) (3.2.2.11)
 

 

Substituting the forward and turning controls in u_L(t) = `+`(`-`(`*`(`/`(1, 2), `*`(u_w(t)))), `*`(`/`(1, 2), `*`(u_v(t)))) and u_R(t) = `+`(`*`(`/`(1, 2), `*`(u_v(t))), `*`(`/`(1, 2), `*`(u_w(t)))) into the following, we get:  

 

`:=`(eqnset_speed_motor_input_PI, eval(eqnset_speed_motor_input_voltage, eqnset_speed_PI)); -1; `:=`(vw_ctl, `union`(`union`(eqnset_speed_motor_input_PI, vw_error), vw_i_error)); -1; u_L(t) = eval(u_L...
`:=`(eqnset_speed_motor_input_PI, eval(eqnset_speed_motor_input_voltage, eqnset_speed_PI)); -1; `:=`(vw_ctl, `union`(`union`(eqnset_speed_motor_input_PI, vw_error), vw_i_error)); -1; u_L(t) = eval(u_L...
`:=`(eqnset_speed_motor_input_PI, eval(eqnset_speed_motor_input_voltage, eqnset_speed_PI)); -1; `:=`(vw_ctl, `union`(`union`(eqnset_speed_motor_input_PI, vw_error), vw_i_error)); -1; u_L(t) = eval(u_L...
`:=`(eqnset_speed_motor_input_PI, eval(eqnset_speed_motor_input_voltage, eqnset_speed_PI)); -1; `:=`(vw_ctl, `union`(`union`(eqnset_speed_motor_input_PI, vw_error), vw_i_error)); -1; u_L(t) = eval(u_L...
`:=`(eqnset_speed_motor_input_PI, eval(eqnset_speed_motor_input_voltage, eqnset_speed_PI)); -1; `:=`(vw_ctl, `union`(`union`(eqnset_speed_motor_input_PI, vw_error), vw_i_error)); -1; u_L(t) = eval(u_L...
`:=`(eqnset_speed_motor_input_PI, eval(eqnset_speed_motor_input_voltage, eqnset_speed_PI)); -1; `:=`(vw_ctl, `union`(`union`(eqnset_speed_motor_input_PI, vw_error), vw_i_error)); -1; u_L(t) = eval(u_L...
`:=`(eqnset_speed_motor_input_PI, eval(eqnset_speed_motor_input_voltage, eqnset_speed_PI)); -1; `:=`(vw_ctl, `union`(`union`(eqnset_speed_motor_input_PI, vw_error), vw_i_error)); -1; u_L(t) = eval(u_L...
 

u_L(t) = `+`(`-`(`*`(`/`(1, 2), `*`(Kpw, `*`(error_w(t))))), `-`(`*`(`/`(1, 2), `*`(Kiw, `*`(i_error_w(t))))), `*`(`/`(1, 2), `*`(Kpv, `*`(error_v(t)))), `*`(`/`(1, 2), `*`(Kiv, `*`(i_error_v(t)))))
u_L(t) = `+`(`-`(`*`(`/`(1, 2), `*`(Kpw, `*`(error_w(t))))), `-`(`*`(`/`(1, 2), `*`(Kiw, `*`(i_error_w(t))))), `*`(`/`(1, 2), `*`(Kpv, `*`(error_v(t)))), `*`(`/`(1, 2), `*`(Kiv, `*`(i_error_v(t)))))
u_L(t) = `+`(`-`(`*`(`/`(1, 2), `*`(Kpw, `*`(error_w(t))))), `-`(`*`(`/`(1, 2), `*`(Kiw, `*`(i_error_w(t))))), `*`(`/`(1, 2), `*`(Kpv, `*`(error_v(t)))), `*`(`/`(1, 2), `*`(Kiv, `*`(i_error_v(t)))))
u_L(t) = `+`(`-`(`*`(`/`(1, 2), `*`(Kpw, `*`(error_w(t))))), `-`(`*`(`/`(1, 2), `*`(Kiw, `*`(i_error_w(t))))), `*`(`/`(1, 2), `*`(Kpv, `*`(error_v(t)))), `*`(`/`(1, 2), `*`(Kiv, `*`(i_error_v(t)))))
(3.2.2.12)
 

u_R(t) = eval(u_R(t), eqnset_speed_motor_input_PI)
u_R(t) = eval(u_R(t), eqnset_speed_motor_input_PI)
 

u_R(t) = `+`(`*`(`/`(1, 2), `*`(Kpv, `*`(error_v(t)))), `*`(`/`(1, 2), `*`(Kiv, `*`(i_error_v(t)))), `*`(`/`(1, 2), `*`(Kpw, `*`(error_w(t)))), `*`(`/`(1, 2), `*`(Kiw, `*`(i_error_w(t)))))
u_R(t) = `+`(`*`(`/`(1, 2), `*`(Kpv, `*`(error_v(t)))), `*`(`/`(1, 2), `*`(Kiv, `*`(i_error_v(t)))), `*`(`/`(1, 2), `*`(Kpw, `*`(error_w(t)))), `*`(`/`(1, 2), `*`(Kiw, `*`(i_error_w(t)))))
u_R(t) = `+`(`*`(`/`(1, 2), `*`(Kpv, `*`(error_v(t)))), `*`(`/`(1, 2), `*`(Kiv, `*`(i_error_v(t)))), `*`(`/`(1, 2), `*`(Kpw, `*`(error_w(t)))), `*`(`/`(1, 2), `*`(Kiw, `*`(i_error_w(t)))))
u_R(t) = `+`(`*`(`/`(1, 2), `*`(Kpv, `*`(error_v(t)))), `*`(`/`(1, 2), `*`(Kiv, `*`(i_error_v(t)))), `*`(`/`(1, 2), `*`(Kpw, `*`(error_w(t)))), `*`(`/`(1, 2), `*`(Kiw, `*`(i_error_w(t)))))
(3.2.2.13)
 

 

The forward speed controller drives both wheels forward, while the turning controller drives each wheel in opposite direction. As such, the forward u[v](t) and turning u[w](t) control inputs relate to the left u[L](t) and right u[R](t) motor inputs as follows: 

 

`:=`(eqnset_speed_motor_input, {u_v(t) = `+`(u_R(t), u_L(t)), u_w(t) = `+`(u_R(t), `-`(u_L(t)))}); -1
`:=`(eqnset_speed_motor_input, {u_v(t) = `+`(u_R(t), u_L(t)), u_w(t) = `+`(u_R(t), `-`(u_L(t)))}); -1
`:=`(eqnset_speed_motor_input, {u_v(t) = `+`(u_R(t), u_L(t)), u_w(t) = `+`(u_R(t), `-`(u_L(t)))}); -1
`:=`(eqnset_speed_motor_input, {u_v(t) = `+`(u_R(t), u_L(t)), u_w(t) = `+`(u_R(t), `-`(u_L(t)))}); -1u_v(t) = eval(u_v(t), eqnset_speed_motor_input)
u_v(t) = eval(u_v(t), eqnset_speed_motor_input)
 

u_v(t) = `+`(u_R(t), u_L(t)) (3.2.2.8)
 

 

u_w(t) = eval(u_w(t), eqnset_speed_motor_input)
u_w(t) = eval(u_w(t), eqnset_speed_motor_input)
 

u_w(t) = `+`(u_R(t), `-`(u_L(t))) (3.2.2.9)
 

 

Writing the motor inputs in terms of the forward and turning controls: 

 

> `:=`(eqnset_speed_motor_input_voltage, solve(eqnset_speed_motor_input, {u_L(t), u_R(t)})); -1
`:=`(eqnset_speed_motor_input_voltage, solve(eqnset_speed_motor_input, {u_L(t), u_R(t)})); -1
`:=`(eqnset_speed_motor_input_voltage, solve(eqnset_speed_motor_input, {u_L(t), u_R(t)})); -1
 

 

Substituting the numeric values of the controller gains, we get: 

 

`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
`:=`(vw_ctl_gains, {Kiv = get_parameter(Text_Speed_Ki_Forward), Kiw = get_parameter(Text_Speed_Ki_Turn), Kpv = get_parameter(Text_Speed_Kp_Forward), Kpw = get_parameter(Text_Speed_Kp_Turn)}); -1; `:=`...
 

{u_L(t) = `+`(`-`(`*`(2.500000000, `*`(error_w(t)))), `-`(`*`(1.500000000, `*`(i_error_w(t)))), `*`(5.000000000, `*`(error_v(t))), `*`(4.000000000, `*`(i_error_v(t)))), u_R(t) = `+`(`*`(5.000000000, `...
{u_L(t) = `+`(`-`(`*`(2.500000000, `*`(error_w(t)))), `-`(`*`(1.500000000, `*`(i_error_w(t)))), `*`(5.000000000, `*`(error_v(t))), `*`(4.000000000, `*`(i_error_v(t)))), u_R(t) = `+`(`*`(5.000000000, `...
{u_L(t) = `+`(`-`(`*`(2.500000000, `*`(error_w(t)))), `-`(`*`(1.500000000, `*`(i_error_w(t)))), `*`(5.000000000, `*`(error_v(t))), `*`(4.000000000, `*`(i_error_v(t)))), u_R(t) = `+`(`*`(5.000000000, `...
{u_L(t) = `+`(`-`(`*`(2.500000000, `*`(error_w(t)))), `-`(`*`(1.500000000, `*`(i_error_w(t)))), `*`(5.000000000, `*`(error_v(t))), `*`(4.000000000, `*`(i_error_v(t)))), u_R(t) = `+`(`*`(5.000000000, `...
{u_L(t) = `+`(`-`(`*`(2.500000000, `*`(error_w(t)))), `-`(`*`(1.500000000, `*`(i_error_w(t)))), `*`(5.000000000, `*`(error_v(t))), `*`(4.000000000, `*`(i_error_v(t)))), u_R(t) = `+`(`*`(5.000000000, `...
(3.2.2.14)
 

 

System Response 

Button# Response with Speed Control 

Forward Speed 

Angular Speed 

ForwardSpeed_SpeedControlled 

Plot_2d  
 

 

AngularSpeed_SpeedControlled 

Plot_2d  
 

 

Motor Control Signals 

Trajectory Animation 

MotorSignals_SpeedControlled 

Plot_2d  
 

 

Trajectory_SpeedControlled 

Plot  
 

 

Heading Control 

Here, we specify the desired heading for the mobile robot to follow. The heading controller is implemented as an outer loop controller to the speed controlled robot system.  Again, we will be using a PI controller in this example. 

System Input 

Button# Heading Control System Input 

The following inputs are applied. The robot is asked to start moving forward and turning at the same time. Then it will keep moving forward while maintaining a constant heading. After that, it will turn again and eventually come to a stop while pointing at the desired heading. 

Forward 

Plot_2d  
 

 

Heading 

Plot_2d  
 

 

 

Controller Definition 

Similar to the speed controller, a PI controller is used for the heading control.  In this case, the output of the controller is the desired turning rate w[ref](t):  

`:=`(eqnset_heading_PI, {w_ref(t) = `+`(`*`(Kptheta, `*`(error_theta(t))), `*`(Kitheta, `*`(i_error_theta(t))))}); -1; w_ref(t) = eval(w_ref(t), eqnset_heading_PI)
`:=`(eqnset_heading_PI, {w_ref(t) = `+`(`*`(Kptheta, `*`(error_theta(t))), `*`(Kitheta, `*`(i_error_theta(t))))}); -1; w_ref(t) = eval(w_ref(t), eqnset_heading_PI)
 

w_ref(t) = `+`(`*`(Kptheta, `*`(error_theta(t))), `*`(Kitheta, `*`(i_error_theta(t)))) (3.3.2.1)
 

 

 

where the heading error (and its integral) is defined as: 

`:=`(theta_error, {error_theta(t) = `+`(theta_ref(t), `-`(theta(t)))}); -1; error_theta(t) = eval(error_theta(t), theta_error)
`:=`(theta_error, {error_theta(t) = `+`(theta_ref(t), `-`(theta(t)))}); -1; error_theta(t) = eval(error_theta(t), theta_error)
 

error_theta(t) = `+`(theta_ref(t), `-`(theta(t))) (3.3.2.2)
 

`:=`(theta_i_error, {diff(i_error_theta(t), t) = error_theta(t)}); -1; diff(i_error_theta(t), t) = eval(diff(i_error_theta(t), t), theta_i_error)
`:=`(theta_i_error, {diff(i_error_theta(t), t) = error_theta(t)}); -1; diff(i_error_theta(t), t) = eval(diff(i_error_theta(t), t), theta_i_error)
 

diff(i_error_theta(t), t) = error_theta(t) (3.3.2.3)
 

 

Parameters for the Heading PI Controller: 

 

Gain 

Value 

Heading Control 

K[P[theta]] 

Embedded component 

K[I[theta]] 

Embedded component 

 

Initial Conditions: 

 

`:=`(theta_IC, {i_error_theta(0) = 0}); -1; theta_IC
`:=`(theta_IC, {i_error_theta(0) = 0}); -1; theta_IC
`:=`(theta_IC, {i_error_theta(0) = 0}); -1; theta_IC
 

{i_error_theta(0) = 0} (3.3.2.4)
 

 

Substituting the numeric values of the controller gains, we get: 

 

> `:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1
`:=`(theta_ctl, `union`(`union`(theta_i_error, theta_error), eqnset_heading_PI)); -1`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1
`:=`(theta_ctl_gains, {Kitheta = get_parameter(Text_Heading_Ki), Kptheta = get_parameter(Text_Heading_Kp)}); -1`:=`(theta_ctl_numeric, eval(theta_ctl, theta_ctl_gains)); -1`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1
`:=`(robot_thetactl_system, `union`(robot_vwctl_system, theta_ctl_numeric)); -1eval(robot_thetactl_system, system_parameters); -1`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1
`:=`(r_system, `union`(`union`(`union`(`union`(`union`(`union`(%, RobotIC), WheelIC), MotorIC), vwctl_IC), theta_IC), theta_input)); -1`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1
`:=`(sol_thetactl, dsolve(r_system, numeric, maxfun = 100000)); -1theta_ctl_numeric
 

{diff(i_error_theta(t), t) = error_theta(t), w_ref(t) = `+`(`*`(1.0, `*`(error_theta(t))), `*`(.8, `*`(i_error_theta(t)))), error_theta(t) = `+`(theta_ref(t), `-`(theta(t)))}
{diff(i_error_theta(t), t) = error_theta(t), w_ref(t) = `+`(`*`(1.0, `*`(error_theta(t))), `*`(.8, `*`(i_error_theta(t)))), error_theta(t) = `+`(theta_ref(t), `-`(theta(t)))}
{diff(i_error_theta(t), t) = error_theta(t), w_ref(t) = `+`(`*`(1.0, `*`(error_theta(t))), `*`(.8, `*`(i_error_theta(t)))), error_theta(t) = `+`(theta_ref(t), `-`(theta(t)))}
(3.3.2.5)
 

 

 

System Response 

Button# System Response with Heading 

Forward Speed 

Heading 

ForwardSpeed_HeadingControl 

Plot_2d  
 

 

Heading_Controlled 

Plot_2d  
 

 

Angular Speed 

Trajectory Animation 

AngularSpeed_HeadingControl 

Plot_2d  
 

 

Trajectory_HeadingControl 

Plot