Engee documentation
Notebook

DC motor control

This example shows a comparison of three DC motor control methods:

  • direct control
  • feedback control
  • LQR control.

Let us compare these methods in terms of sensitivity to load disturbances.

Problem statement

In an anchor-controlled DCT, the input voltage $V_a$ controls the angular speed of the motor shaft.

xxdcdemofigures_01.png

This example shows two ways of controlling a DPT to reduce the sensitivity of $\omega$ to changes in load (changes in torque produced by the motor load).

xxdcdemofigures_02.png

A simplified DC motor model is shown above. The torque parameter $T_d$ models load disturbances. Speed fluctuations caused by such disturbances should be minimised.

Let's set the motor parameters. In this example, the physical constants are:

In [ ]:
Pkg.add(["LinearAlgebra", "RobustAndOptimalControl", "ControlSystems", "ControlSystemsBase"])
In [ ]:
import Pkg; 
Pkg.add("ControlSystemsBase")
Pkg.add("RobustAndOptimalControl")
Pkg.add("LinearAlgebra")
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
   Resolving package versions...
  No Changes to `~/.project/Project.toml`
  No Changes to `~/.project/Manifest.toml`
   Resolving package versions...
    Updating `~/.project/Project.toml`
  [37e2e46d] + LinearAlgebra
  No Changes to `~/.project/Manifest.toml`
In [ ]:
using ControlSystems, ControlSystemsBase, RobustAndOptimalControl, LinearAlgebra

R = 2.0 ;   
L = 0.5;     
Km = 0.1;   
Kb = 0.1;    
Kf = 0.2;    
J = 0.02;    

Let's build a model of a DPT with two inputs ($V_a$,$T_d$) and one output ($w$). First of all, let's define the description of the blocks of the structural diagram presented above in the form of transfer functions.

In [ ]:
h1 = tf([Km], [L, R])
h2 = tf([1], [J, Kf]) 
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoRational{Float64}}
    1.0
-----------
0.02s + 0.2

Continuous-time transfer function model

Let's establish links between the blocks. Assign the names of input and output signals, define summarising blocks and establish links between blocks using the function connect().

Assign names to the input and output signals.

In [ ]:
H1 = named_ss(h1, x = :xH1, u = :uH1, y = :yH1)
H2 = named_ss(h2, x = :xH2, u = :uH2, y = :yH2)
Kb = named_ss(ss(Kb), x = :xKb, u = :uKb, y = :yKb)

Specify the signals that are input and output from the summing units.

In [ ]:
Sum1 = sumblock("uH1 = Va - yKb")
Sum2 = sumblock("uH2 = yH1 + Td")

Establish correspondences between the outputs and inputs of the blocks.

In [ ]:
connections = [
    :uH1 => :uH1;
    :yH1 => :yH1;
    :uH2 => :uH2;
    :yH2 => :uKb;
    :yKb => :yKb;   
]

Set external input signals and output signal.

In [ ]:
w1 = [:Va, :Td]
z1 = [:yH2]

Pass the parameters to the function connect() to obtain the systems model.

In [ ]:
dcm = connect([H2, H1, Kb, Sum1, Sum2], connections; z1, w1, verbose = true)

Now let's see the response to a single step impact.

In [ ]:
V_a = dcm[1,1];
plot(stepinfo(step(V_a,2.5)))
Out[0]:

When a single step action is applied to the input ($Td=0$), the steady-state value of the output signal is 0.244.

Direct control of a DC motor

The first control variant is direct control. The desired value of angular velocity ($w_{ref}$) will be input to the system and the external torque ($Td$) will be modelled on the system.

xxdcdemofigures_03.png

The direct coupling gain $K_{ff}$ must be set to the inverse of the DC gain from $Va$ to $w$.

In [ ]:
Kff = 1/dcgain(V_a)[1]
Out[0]:
4.099999999999999

To evaluate the effectiveness of the direct coupled design under load disturbances, simulate the response to a step command $w_{ref}=1$ with a disturbance of $Td = -0,1 Нм$ between $t=5 и t=10$ seconds:

In [ ]:
t = 0:0.01:15
Td = -0.1 * (5 .< t .< 10)          
u = hcat( ones( length(t) ), Td )       

cl_ff = dcm * Diagonal( [Kff, 1] )   

h_1 = lsim( cl_ff, u, t )
plot( h_1, label = "Прямое управление, h_1(t)" )
plot!( t, Td, label = "Внешний возмущающий момент, Td" )
Out[0]:

Feedback system

Let's consider the second variant of control and describe the feedback control structure.

xxdcdemofigures_04.png

To ensure zero steady-state error, we use the controller $C(s)$ as a gain integrator.

To determine the gain K, we can use the root-mean-square hodograph method applied to open-loop transmission ($1/s * (Va \to w)$):

In [ ]:
rlocusplot( ss( tf( 1, [1, 0] ) ) * V_a )
Out[0]:

Hover over the curves to familiarise yourself with the values of the gain and the corresponding pole. It can be seen that the trajectories of the two roots cross the imaginary axis. At these points, $K\approx55$. For our system to remain stable, we need to choose $K<55$. Let's choose $K = 5$.

In [ ]:
K = 5;

Name the input and output signals.

In [ ]:
C = named_ss( tf( K,[1, 0] ), x=:xC, u=:e, y=:Va )
Out[0]:
NamedStateSpace{Continuous, Float64}
A = 
 0.0
B = 
 2.0
C = 
 2.5
D = 
 0.0

Continuous-time state-space model
With state  names: xC
     input  names: e
     output names: Va

Specify the signals that are input and output from the summing units.

In [ ]:
sum = sumblock( "e = w_ref - yH2" )
Out[0]:
sumblock: NamedStateSpace{Continuous, Float64}
D = 
 1.0  -1.0

Continuous-time state-space model
With state  names: 
     input  names: w_ref yH2
     output names: e

Establish correspondences between the outputs and inputs of the blocks.

In [ ]:
connections1 = [
    :e => :e;
    :Va => :Va;
    :yH2 => :yH2
]
Out[0]:
3-element Vector{Pair{Symbol, Symbol}}:
   :e => :e
  :Va => :Va
 :yH2 => :yH2

Set the external input signals and output signal

In [ ]:
w1 = [ :w_ref, :Td ]
z1 = [ :yH2 ]
Out[0]:
1-element Vector{Symbol}:
 :yH2

Pass the parameters to the function connect() to obtain the system model.

In [ ]:
cl_rloc = connect( [sum, C, dcm], connections1; w1, z1 )
Out[0]:
NamedStateSpace{Continuous, Float64}
A = 
 0.0   -12.5      0.0
 0.0   -10.0      3.2
 1.25   -0.3125  -4.0
B = 
 2.0  0.0
 0.0  8.0
 0.0  0.0
C = 
 0.0  6.25  0.0
D = 
 0.0  0.0

Continuous-time state-space model
With state  names: xC##feedback#237 xH2##feedback#227##feedback#237 xH1##feedback#227##feedback#237
     input  names: w_ref Td
     output names: yH2

Let us plot the output signals for direct control and feedback control.

In [ ]:
h_2 = lsim( cl_rloc, u, t )       
plot( h_1, label = "Прямое управление, h_1(t)" )
plot!( h_2, label = "Управление с обратной связью, h_2(t)" )
plot!( t, Td, label = "Внешний возмущающий момент, Td" )
Out[0]:

The result of feedback control is much better than the direct control method. However, there are peaks at the beginning and at the end of the action $Td$.

Controlling a DC motor with a lazy-quadratic controller

To further improve performance, let's try to design a linear-quadratic regulator (LQR) for the feedback structure shown below.

xxdcdemofigures_05.png

In addition to the integral, the LQR circuit also uses the state vector $x=(i,w)$ to synthesise the control voltage $Va$. The resulting voltage is $$ Va = K1w+K2\frac{w}{s}+K3i $$ where $i$ is the armature current

To better suppress perturbations, we use a cost function that "penalises" large integral error. For example,

$$ C = \int_0^\infty (20q(t)^2+\omega(t)^2+0.01V_a(t)^2)\,\mathrm{d}x $$

where

$$ q(s)=\frac{\omega(s)}{s} $$

We calculate the optimal LQR gain for this cost function.

Add the output w/s to the model dcm.

In [ ]:
dc_aug = [ 1 ; ss( tf( 1,[1, 0] ) ) ] * V_a 
Out[0]:
NamedStateSpace{Continuous, Float64}
A = 
 0.0    6.25     0.0
 0.0  -10.0      3.2
 0.0   -0.3125  -4.0
B = 
 0.0
 0.0
 0.5
C = 
 0.0  6.25  0.0
 1.0  0.0   0.0
D = 
 0.0
 0.0

Continuous-time state-space model
With state  names: ##x#239 xH2##feedback#227 xH1##feedback#227
     input  names: Va
     output names: ##y#2411 ##y#2412

Set the weight matrices Q and R, and synthesise the controller using the function lqr.

In [ ]:
Q = [ 20 0 0; 0 1 0; 0 0 1 ]
R = 0.01
K_lqr = lqr( dc_aug, Q, R )
Out[0]:
1×3 Matrix{Float64}:
 44.7214  25.5262  14.1526

Then we obtain a closed-loop system.

Let's add the output x, using add_output(). But for this we need the variable dcm to have the data type StateSpace, as required by the function add_output(). So we do the conversion using ss().

In [ ]:
dcm_new = add_output(ss(dcm), I(2))
Out[0]:
StateSpace{Continuous, Float64}
A = 
 -10.0      3.2
  -0.3125  -4.0
B = 
 0.0  8.0
 0.5  0.0
C = 
 6.25  0.0
 1.0   0.0
 0.0   1.0
D = 
 0.0  0.0
 0.0  0.0
 0.0  0.0

Continuous-time state-space model

Let's add an integrator.

In [ ]:
C = K_lqr * append( tf(1, [1, 0]), tf(1), tf(1) ) 
Out[0]:
TransferFunction{Continuous, ControlSystemsBase.SisoRational{Float64}}
Input 1 to output 1
44.72135954999597
-----------------
      1.0s

Input 2 to output 1
25.526213567574707
------------------
       1.0

Input 3 to output 1
14.152551403054153
------------------
       1.0

Continuous-time transfer function model

Description of open loop control system with LQR.

In [ ]:
OL = dcm_new * append( C, ss(1) ) 
Out[0]:
StateSpace{Continuous, Float64}
A = 
 -10.0      3.2  0.0
  -0.3125  -4.0  2.795084971874748
   0.0      0.0  0.0
B = 
 0.0   0.0                0.0                8.0
 0.0  12.763106783787354  7.076275701527076  0.0
 8.0   0.0                0.0                0.0
C = 
 6.25  0.0  0.0
 1.0   0.0  0.0
 0.0   1.0  0.0
D = 
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0

Continuous-time state-space model

Description of closed-loop control system with LQR.

In [ ]:
CL = feedback( OL, I(3), U1=1:3, Y1=1:3 )
Out[0]:
StateSpace{Continuous, Float64}
A = 
 -10.0                  3.2                0.0
 -13.075606783787354  -11.076275701527077  2.795084971874748
 -50.0                  0.0                0.0
B = 
 0.0   0.0                0.0                8.0
 0.0  12.763106783787354  7.076275701527076  0.0
 8.0   0.0                0.0                0.0
C = 
 6.25  0.0  0.0
 1.0   0.0  0.0
 0.0   1.0  0.0
D = 
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0
 0.0  0.0  0.0  0.0

Continuous-time state-space model

Transfer function (w_ref,Td)$\to$ w

In [ ]:
cl_lqr = CL[ 1, 1:3:4 ]
Out[0]:
StateSpace{Continuous, Float64}
A = 
 -10.0                  3.2                0.0
 -13.075606783787354  -11.076275701527077  2.795084971874748
 -50.0                  0.0                0.0
B = 
 0.0  8.0
 0.0  0.0
 8.0  0.0
C = 
 6.25  0.0  0.0
D = 
 0.0  0.0

Continuous-time state-space model

Finally, let's compare the three DCT control schemes by plotting the output plots.

In [ ]:
h_3 = lsim( cl_lqr, u, t )
plot( [h_1, h_2, h_3], label=["Прямое управление, h_1(t)" "Управление с обратной связью, h_2(t)" "Регулирование LQR, h_3(t)"] )
plot!( t, Td, label = "Внешний возмущающий моомент, Td" )
Out[0]:

By analysing the graph, it can be seen that the peaks of the output signal have become smaller compared to the previous control method.

Conclusion

In this example the creation of a model of the control object - a DC motor was considered. The comparison of three methods of controlling the DCT has been carried out. As a result of analysing the obtained system responses, the control method with LQR turned out to be the most effective and best fought against the influence of external disturbing torque.