
MEC4127F: Introduction to Robotics
Chapter 11: Position control design for quadcopters
11.1 Introduction
In Chapter 10 we were able to design orientation controllers for the roll and pitch channels, and an angular rate controller for the yaw channel. The feedback mechanism for the roll and pitch controllers was predicated on the idea of thrust vectoring, where a desired thrust vector in
was specified, which inferred the orientation error that could be used by the associated attitude controllers. We can now take the next step and design a feedback controller for the position behaviour of the quadcopter, as well as make use of thrust vectoring to convert information from the outer loop's demands, to the inner loops requirements. As first introduced in Chapter 10, Figure 11.1 gives a high-level overview of the full control system, which includes the outer loop position controller and inner loop attitude controller. Figure 11.1: High-level block diagram of cascaded control scheme.
The main elements that necessitate this scheme are repeated below.
- control allocation — mapping desired thrust and torque vectors to the rotor speeds;
- dynamic analysis — assessing the dynamics of the system in order to inform an appropriate flight envelope;
- attitude control design — design a controller that can stabilise the orientation of the quadcopter whilst also meeting the prescribed specifications;
- thrust vectoring — relate the position control command to the orientation error in order to dictate orientation changes required;
- position control design — design a controller that can stabilise the translation of the quadcopter whilst also meeting the prescribed specifications;
Points 1-3 were covered in Chapter 10, and points 4-5 will be dealt with in this chapter, starting with the formulation of the desired thrust vector based on control action in the translational loop.
11.2 Thrust vectoring
11.2.1 Recap
As discussed in Chapter 10, one can make use of the concept of thrust vectoring to determine the orientation required in order to point
in a particular direction in
. Because our body-frame thrust vector
is parallel to
, this approach ultimately dictates the direction in
in which our thrust vector points. Based on Chapter 9, we have already shown that the translational dynamics of our quadcopter can be approximated by
where m is the mass of the quadcopter,
is the translational acceleration of the quadcopter in
,
is the rotation matrix describing the orientation in
, and
is the gravitational force. Noting that
, the equation above can also be written as Considering
, with
, we are able to directly determine desired values for
based on setting the appropriate rotor speeds: Assuming our orientation control design from Chapter 10 is also effective, we can also dictate how to orient the quadcopter, after some settling period that relates to the bandwidth of our attitude control system. We therefore can think of
as a overall control vector from the translational control system, which indicates the desired thrust that is required for a particular translational motion. 11.2.2 Feedforward control
If we know the desired acceleration of our quadcopter, namely,
, we can solve the translational dynamics equation for
based on The equation above can be thought of as feedforward control and describes the inverse dynamics of the quadcopter, which relates the desired acceleration to the corresponding desired thrust vector. In theory, if we knew
and m exactly, if the control allocation mapping from rotor speeds to thrust and torque was exact and instantaneous, and if there were no external disturbances acting on the quadcopter, we could use the approach above to manoeuvre our quadcopter around based on the desired acceleration (which possibly originates from a twice-differentiable trajectory, for example based on Chapter 7). The feedforward approach is illustrated in Figure 11.2. Figure 11.2: Block diagram of feedforward control scheme.
11.2.3 Feedback control
Unfortunately, the assumption that we have perfect knowledge of all system parameters, and that there are no external disturbances acting on the system, is very unrealistic. For this reason, the approach above would not be very reliable. Fortunately, we have a very simple means of accounting for unmodelled dynamics and external dynamics — feedback control! In essence, we can augment the feedforward approach above with feedback control action that is driven by a position error. Assuming a position controller is designed such that the control action is indicated by
, the augmented desired thrust vector in
is described by Control action term
is then responsible for any behaviour that results in
, such as from aerodynamic drag on the quadcopter body, or wind disturbances. The feedforward-feedback approach is illustrated in Figure 11.3. Figure 11.3: Block diagram of feedforward-feedback control scheme.
Note that if the desired acceleration is not known, one can simply set
. Control action term
will be designed in a later section, based on the same frequency domain design principles as used in Chapter 10. 11.2.4 Control allocation
Once
has been determined (be it from Section 11.2.2 or Section 11.2.3) the corresponding desired thrust magnitude and orientation error required must be determined. Recalling that
, and noting that rotation matrices preserve the lengths of rotated vectors, it follows that the two-norm (magnitude) of the thrust vector is given by where
by definition. We therefore have an easy means of determining the amount of net thrust to produce if we know
. Recall from Chapter 10 that thrust vectoring could be used to determine the orientation error in
using the mapping Physically,
represents the desired direction and magnitude of
when described in
. This implies that
and
are parallel to each other. By extension, we can determine
, indicating the direction of the frame
z-axis in
, as The desired z-axis direction represented in
follows as We can then determine the orientation error, framed as exponential coordinates, as
, where Example: Control allocation
The code block below provides a visualisation of the desired quadcopter orientation as a result of specifying
and then determining
. To simplify things, control action
is set to zero, which corresponds with the ideal case of having no unmodelled dynamics or disturbances. The desired translational acceleration and current orientation (in quaternion form) are adjustable. alpha_e = acos( dot(zb,zd2b) );
v_e = 1/sin(alpha_e)*cross(zb,zd2b);
dq = [cos(alpha_e/2) sin(alpha_e/2)*v_e'];
q_des = quatmultiply(q,dq);
% plotTransforms([0 0 0],q,"FrameAxisLabels","on","FrameLabel","W")
plotTransforms([0 0 0],q_des,"MeshFilePath",'multirotor.stl',"MeshColor","red","FrameAxisLabels","on","FrameLabel","D")
xlim([-1 1]),ylim([-1 1]),zlim([-1 1])
title('Desired quadcopter orientation as a result of specifying desired acceleration')
11.3 Translational open-loop plant model
11.3.1 Closed-loop rotational dynamics
Using the content presented in Chapter 10, we were able to design feedback controllers for the roll, pitch, and yaw-rate of our attitude system. Using the idea of thrust vectoring, the resulting closed-loop behaviour of the roll and pitch systems will largely dictate the responsiveness of the quadcopter in translational motion. For example, if the roll and pitch controllers are slow in adjusting the orientation of the quadcopter, then by extension, vectoring the thrust on the quadcopter will be equally slow. We therefore want to capture the closed-loop dynamics of the attitude system when designing our position controller, in order to capture the true nature of how translation requires reorienting the quadcopter.
We will assume that the roll and pitch channels are approximately identical, which is a fair assumption when
and the feedback control schemes are identical. The roll/pitch loop transfer function is given by where
is the open-loop roll/pitch plant that we introduced in Chapter 10, and
is the corresponding feedback controller. We can then determine the closed-loop transfer behaviour as which gives us an indication of how quickly the orientation of the quadcopter can be adjusted using roll/pitch motion when in closed loop, and by extension, how quickly the thrust vector direction can be changed.
11.3.2 Thrust vector dynamics
Considering the translational dynamics again of
thrust vector
serves as the signal that we ultimately have control over. We can write this thrust vector as Recalling that
the desired net thrust,
can be related to the achieved net thrust in the Laplace domain based on where
is the delay period resulting from the motor speed delay from Vector
, representing
when described in
, encodes the closed-loop roll/pitch behaviour of the quadcopter and can therefore be related to the desired vector using where
describes the closed-loop roll/pitch transfer behaviour. In other words, the closed-loop roll/pitch behaviour dictates how quickly the quadcopter can reorient
in
. Using the information above,
can be described by in the Laplace domain as where
by definition. Assuming that the gravitational force has been approximately compensated for using feedforward based on
and setting
for now, the translational dynamics of the quadcopter, stemming from the dynamic equation of
can be represented in transfer function form as
.We can then relate the desired thrust vector to the actual thrust vector, which yields
The transfer function
describes the open-loop plant model relating the desired thrust vector to the dynamic position of the quadcopter in 3D space. We can therefore use this model when designing our translational controllers if we know
, m, and
. Note that the result is somewhat conservative under certain motions. Specifically, if motion is to take place along
, in other words, parallel to the thrust vector, then the dynamics associated with adjusting the thrust vector —
— do not actually come into play. That being said, general quadcopter motion of interest usually involves reorienting the platform, which is correctly governed by the equation above. 11.4 Translational control design
The information obtained in Section 11.3 can be used to design controllers for motion in 3D space. Given that the transfer behaviour from desired thrust vector to position in
is given by which possesses two integrators, a delay term, and additional phase lag from
, derivative action is required in the position controller to stabilise the closed-loop position system. As with the attitude dynamics, if there are no external disturbances acting on the position system, we can get away with designing a PD controller. If, however, our quadcopter encounters real-world disturbances, such as aerodynamic drag on the body or wind forces, we would need integral action in the form of a PID controller. Assuming the more realistic latter case, we can implement a PID controller of the form
,where α and β is the zero and pole of
, respectively,
is integral time constant, andK is a gain applied at all frequencies. As with the attitude control design, we can first design the PID controller as if it is a PD controller, after setting
, and then subsequently reduce
as far as allowed by the stability boundaries after satisfying the design requirements. Example: translational control design
We will use the attitude system parameters from the examples in Chapter 10 to determine the closed-loop rotational system,
. Our roll/pitch open-loop plant was given by and the designed feedback PID controller was given by
The closed-loop transfer function follows as
Po = 1/(Jxx*s^2)*exp(-s*.01);
Go = .005*(1+s/0.325)/(1+s/42.44)*(1+5*s)/(5*s)
Go =
1.061 s^2 + 0.557 s + 0.06896
-----------------------------
1.625 s^2 + 68.97 s
Continuous-time transfer function.
Model Properties
To = feedback(Po*Go,1)
To =
A =
x1 x2 x3 x4
x1 -42.44 -652.9 -342.8 -42.44
x2 1 0 0 0
x3 0 1 0 0
x4 0 0 1 0
B =
u1
x1 32
x2 0
x3 0
x4 0
C =
x1 x2 x3 x4
y1 0 20.4 10.71 1.326
D =
u1
y1 0
(values computed with all internal delays set to zero)
Internal delays (seconds): 0.01
Continuous-time state-space model.
Model Properties
Using this information, we can form the open-loop translational plant
which will be used for our design of each translational channel.
P = To/m/(s^2)*exp(-s*.01);
The outer loop bandwidth needs to be lower than the inner loop, as the position behaviour relies on the attitude behaviour to settle before achieving the desired motion. We will therefore set the bandwidth of the outer loop to be sufficiently small relative to that of the inner loop. The desired specifications follow as
- a desired
settling time requirement of
seconds (four times that of the inner loop) and, - an allowed percentage overshoot of
.
This results in the following design requirements:
rad/s.zeta = -log(OS/100)/sqrt( pi^2+log(OS/100)^2 );
wp = wn*sqrt(1-2*zeta^2);
Ma = 1/( 2*zeta*sqrt(1-zeta^2) ); %overbound
According to the design methodology detailed in Section 10.4.3, we first set
and then design the feedback controller as if its a PD controller. Design of the PD controller requires us to first set
and set
, followed by choosing α based on the desired phase lead at the chosen frequency design point. Once α is chosen, β is determined algebraically. Finally, K can be readjusted as required. The code block below allows for design of the PID controller, as well as the necessary visualisation for purposes of synthesis. We start by setting:
G = K*(1+s/alpha)/(1+s/beta)*(1+Ti*s)/(Ti*s);
phi = linspace(0,2*pi,1e4);
mag_K = 20*log10( abs(K) );
phi_K = angle( K )*180/pi;
if( phi_K(i) > 0), phi_K(i) = phi_K(i)-360; end
plot( phi_K(2:end-1),-mag_K(2:end-1),'--b',LineWidth=2 )
plot( phi_K(2:end-1),-mag_K(2:end-1),'-g',LineWidth=2 )
Lw = squeeze( freqresp(L,wp) );
ang_Lw = angle(Lw)*180/pi;
plot(ang_Lw,20*log10(abs(Lw)),'o',MarkerFaceColor='g',MarkerEdgeColor='k')
[mag,phase] = nichols(L);
plot(squeeze(phase),squeeze(20*log10(mag)))
plot(-180,0,'ro',MarkerFaceColor='r')
legend('$|T(j\omega)|\leq M_A$','$|T(j\omega)|\geq M_B$',Interpreter="latex")
xlim([-360,0]),ylim([-40,40])
title('Representation of position loop transfer function in log-polar plane')
We see that we are currently not meeting either design requirement, as expected. We therefore must choose a design frequency point where we are going to add the most phase, as well as the phase required at that design point. By inspection, we need approximately
of phase lead to try avoid the stability boundary. Using
rad/s, we can then determine the required zero and pole locations of our controller using
,and
.alpha = w_max/tan( (phi_max+pi/2)/2 )
This yields the PD parameters of
rad/s. Updating our simulation code block above shows that we have provided sufficient phase at the design frequency but now have too much gain. We therefore reduce the gain to
, which meets both design requirements. The final step is to reduce
as far as possible. A value of
is close to as small as we can go before hitting the stability limit. Checking the time-domain step response shows that we meet both user specifications in the time domain too.
yline(1+OS/100,'--b',['$\% OS=$',num2str(OS),'$\%$'],'Interpreter','latex')
xline(Ts,'--r',['$t_s=$',num2str(Ts),' s'],'Interpreter','latex','LabelVerticalAlignment','bottom')
title('Simulated step response of closed-loop position system')
Our designed PID controller, which is applicable to all three translational channels, is given by
Note that in certain cases when designing a PID controller, we may need to update the
values after choosing
, as well as the peak frequency value (where the largest phase lead is applied). 11.5 Implementation of control scheme
The code block below provides a nonlinear 3D closed-loop simulation of the quadcopter's attitude and translational using the controllers that were designed in the preceding examples. The controllers are implemented using pseudo-continuous-time difference equations.
J = diag( [Jxx,Jyy,Jzz] );
desiredMotorSpeeds_past = zeros(4,1);
de_p = (e_p-e_p_past)/dT;
dde_p = (de_p-de_p_past)/dT;
ddu_p = (-Ti*du_p + K*e_p + K*(1/alpha+Ti)*de_p + K*Ti/alpha*dde_p)/(Ti/beta);
f_sigma_des = norm(F_des);
z_des = F_des/f_sigma_des;
alpha_e = acos( dot(zb,zd2b) );
v_e = cross(zb,zd2b)/sin(alpha_e);
de_or = (e_or-e_or_past)/dT;
dde_or = (de_or-de_or_past)/dT;
%roll/pitch PID controller
ddu_or(1:2) = (-Ti*du_or(1:2) + K*e_or(1:2)+K*(1/alpha+Ti)*de_or(1:2)+K*Ti/alpha*dde_or(1:2))/(Ti/beta);
du_or(1:2) = du_or(1:2) + dT*ddu_or(1:2);
u_or(1:2) = u_or(1:2) + dT*du_or(1:2);
du_or(3) = K/Ti*(-w(3))+K*(-w_dot(3));
u_or(3) = u_or(3)+dT*du_or(3);
desiredMotorSpeeds = invA*[f_sigma_des; u_or];
motorSpeeds = desiredMotorSpeeds_past;
% motorSpeeds = desiredMotorSpeeds;
m = A(2:4,:)*motorSpeeds;
w_dot = J\( m-cross(w,J*w) );
dq = [cos(alpha/2) sin(alpha/2)*v'];
Fb(3) = A(1,:)*motorSpeeds;
ddp = 1/mass*( R*Fb+Gw );
desiredMotorSpeeds_past = desiredMotorSpeeds;
plotTransforms(p',q,"MeshFilePath",'multirotor.stl',"MeshColor","red","FrameAxisLabels","on","FrameLabel","B")
xlim([-2 2]),ylim([-2 2]),zlim([-1 3])
z_des_array = [z_des_array z_des];
%determine zb wrt {w} and zd wrt {w}
z_b2w = quatrotate(quatconj(q_array),[0 0 1]);
figure(2),clf,sgtitle('Comparison desired and actual z axes with respect to world frame')
subplot(3,1,1),plot(time,z_b2w(:,1)),hold on, plot(time,z_des_array(1,:))
xlabel('time'),ylabel('x-axis'),legend('${^W\hat{\bf z}_B}$','${^W\hat{\bf z}_D}$',"interpreter","latex")
subplot(3,1,2),plot(time,z_b2w(:,2)),hold on, plot(time,z_des_array(2,:))
xlabel('time'),ylabel('y-axis'),legend('${^W\hat{\bf z}_B}$','${^W\hat{\bf z}_D}$',"interpreter","latex")
subplot(3,1,3),plot(time,z_b2w(:,3)),hold on, plot(time,z_des_array(3,:))
xlabel('time'),ylabel('z-axis'),legend('${^W\hat{\bf z}_B}$','${^W\hat{\bf z}_D}$',"interpreter","latex")
figure(3),clf,sgtitle('Comparison desired and actual position of quadcopter')
subplot(3,1,1),plot(time,p_array(1,:)),hold on, line([0 simTime],[p_des(1) p_des(1)])
xlabel('time'),ylabel('x-axis'),legend('${^W{\bf p}_x}$','${^W{\bf p}^*_x}$',"interpreter","latex")
subplot(3,1,2),plot(time,p_array(2,:)),hold on, line([0 simTime],[p_des(2) p_des(2)])
xlabel('time'),ylabel('y-axis'),legend('${^W{\bf p}_y}$','${^W{\bf p}_y^*}$',"interpreter","latex")
subplot(3,1,3),plot(time,p_array(3,:)),hold on, line([0 simTime],[p_des(3) p_des(3)])
xlabel('time'),ylabel('z-axis'),legend('${^W{\bf p}_z}$','${^W{\bf p}_z^*}$',"interpreter","latex")