Demonstrate a spacecraft in orbit pointing at a target on the Earth

Since version 8.
------------------------------------------------------------------------
See also C2DelZOH, PIDMIMO, AU2Q, CoordinateTransform, LatLonToR, Q2AU,
QForm, QMult, QPose, U2Q, Constant, AnimateVectors, Map, RK4, Unit,
Date2JD, JD2T, OrbRate, RVFromKepler, Period, DMS2Rad, GMSTime,
TruEarth, DeltaQTarget, AttitudeTarget
------------------------------------------------------------------------

Contents

%--------------------------------------------------------------------------
%   Copyright (c) 2008 Princeton Satellite Systems, Inc.
%   All rights reserved.
%--------------------------------------------------------------------------

Setup the orbit

%----------------

Constants

%--------------
Re = 6378.14; % radius of Earth (km)

Ground target

%--------------
tgt.latitude  = DMS2Rad( 51, 15, 44.20 ); % latitude to point at (rad)
tgt.longitude = DMS2Rad( -2, 17, 17.27 ); % longitude to point at (rad)
tgt.u         = [1;0;0];                  % body vector to point

Simulation parameters

%----------------------------
jD       = Date2JD+100;  % today's date in Julian date format
alt      = 400;      % altitude of orbit (km)
tSpan    = 3*60;     % time span to simulate (seconds)
tSamp    = 0.25;     % control sampling time (seconds)

Compute orbital elements and show ground track with target

%-----------------------------------------------------------
time  = 0:tSamp:tSpan;
T     = Period(Re+alt);                       % orbit period (sec)
gms   = GMSTime( jD )*pi/180;    % Greenwich mean time at jD (deg)
rA    = gms-pi/2+tgt.longitude;  % Right ascension (rad)
inc   = tgt.latitude;            % Inclination (rad)
n     = OrbRate( Re+alt );       % mean orbit rate (rad/s)
M     = pi/2 - tSpan/2*n;        % initial mean anomaly
el    = [Re+alt, inc, rA, 0, 0, M];    % orbital elements
t     = linspace(0,tSpan,30);
[r,v] = RVFromKepler( el, t );
lla   = zeros(size(r));
for i=1:length(t),
   lla(:,i) = CoordinateTransform('eci','llr',r(:,i),jD+t(i)/86400);
end
Map('Earth','2d')
plot(lla(2,:)*180/pi,lla(1,:)*180/pi,'y')
plot(tgt.longitude*180/pi,tgt.latitude*180/pi,'r.','markersize',20)

Initial conditions for attitude dynamics

q0          = [1;0;0;0];   % Initial ECI to Body quaternion
w0          = [0;0;0];     % Initial angular rates of Body [rad/sec]
inertia     = eye(3); % inertia matrix [kg-m^2]
noiseSigma  = 0;        % 1-sigma noise level for pointing knowledge [rad]

The plant: rigid body model

Our plant (the rigid body spacecraft) is a double integrator. The input to the the plant is a commanded angular acceleration. The output is an angular rotation.

Compute the plant statespace system

ap = [0 1;0 0]; bp = [0;1]; cp = [1 0]; dp = 0;

The controller

We will now design a PID controller with input "u" and output "y". It will have the following transfer function:

             Kr s         u
 y = Kp u +  ---- u + Ki ---
            s + wR        s

The gains (Kp, Kr, Ki) and the derivative roll-off term (wR) will be computed using the PIDMIMO function. It will compute these controller parameters so that the closed-loop system (the controlled spacecraft) will have the desired properties. We specify the desired properties in terms of: * natural frequency * damping ratio * integrator time constant * derivative roll-off frequency

zeta        = 0.7071;      % damping ratio (critically damped)
omega       = 0.3;         % natural frequency
tauInt      = 100;         % integrator time constant (sec)
omegaR      = 4;           % derivative roll-off
inr         = 1;           % unit inertia - controller outputs an acceleration
rateLimit   = .25;         % maximum angular rate [rad/s]
stepLimit   = rateLimit*tSamp;

Calculate state-space control system matrices:

[ak, bk, ck, dk, gains] = PIDMIMO( inr, zeta, omega, tauInt, omegaR);
[akd,bkd] = C2DelZOH(ak,bk,tSamp);
invInertia = inv(inertia);

Simulation

We will simulate a point mass orbit and a rigid body

xOrb = [r(:,1);v(:,1)];
xAtt = [q0;w0];

mu = Constant('mu earth');
orbitRHS = @(x,t) FOrbCart(x,t,0,mu);

d = struct;
d.qECIToBody = q0;
d.rECI = xOrb(1:3);
d.jD = jD;

xRoll = [0;0];
xPitch= [0;0];
xYaw  = [0;0];
xPlot = zeros(13,length(time));
trq   = zeros(3,length(time));
pointingError = zeros(1,length(time));
uTB           = zeros(3,length(time));
angleError    = trq;
qECIToTargetOld = q0;
for k = 1:length(time)
   xPlot(:,k) = [xAtt;xOrb]; % record
   qECIToBody = xAtt(1:4);   % rename for clarity

   % Compute the new target quaternion
   %----------------------------------
   d.qECIToBody = qECIToBody;
   d.rECI = xOrb(1:3);
   d.jD = jD+time(k)/86400;
   qTarget = AttitudeTarget( 'latlon', d, tgt );

   % Limit the total angular change
   %-------------------------------
   [qTargetToBody,qECIToTargetOld] = DeltaQTarget(qTarget,qECIToBody,...
                                                qECIToTargetOld,stepLimit);
   qBodyToTarget = QPose(qTargetToBody);

   qTToB = QMult( QPose(qTarget), qECIToBody );
   uTB(:,k) = QForm(qTToB,tgt.u);
   pointingError(k) = acos(dot(uTB(:,k),tgt.u));
   angleError(:,k) = 2*qBodyToTarget(2:4) + randn(3,1)*noiseSigma;

   % The delta form of the controller
   %---------------------------------
   acc    = zeros(3,1);
   acc(1) =          ck*xRoll   + dk*angleError(1,k);
   xRoll  = xRoll  + akd*xRoll  + bkd*angleError(1,k);
   acc(2) =          ck*xPitch  + dk*angleError(2,k);
   xPitch = xPitch + akd*xPitch + bkd*angleError(2,k);
   acc(3) =          ck*xYaw    + dk*angleError(3,k);
   xYaw   = xYaw   + akd*xYaw   + bkd*angleError(3,k);
   tExt  = -inertia*acc;

   % Numerical integration of the dynamics:
   xAtt = RK4( 'FRB', xAtt, tSamp, time(k), inertia, invInertia, tExt );
   xOrb = RK4( orbitRHS, xOrb, tSamp, time(k) );
   trq(:,k) = tExt;
end

plots

Plot2D(time,xPlot(1:4,:),'Time (s)','Quaternion','Inertial to Body Quaternion');
legend('qS','qX','qY','qZ');
Plot2D(time,xPlot(5:7,:)*180/pi,'Time (s)','Body rates [deg/s]','Body rates');
legend('wX','wY','wZ');
Plot2D(time,trq,'Time (s)','Control Torques [Nm]','Control Torques');
legend('Tx','Ty','Tz'),...
Plot2D(time,angleError*180/pi,'Time (s)','Angular Error Input to Control Law [deg]','Control Tracking Error');
legend('eX','eY','eZ');
Plot2D(time,pointingError*180/pi,'Time (s)','Pointing Error [deg]','Pointing Error');

animation

animate the target vector in the Body frame during the transient period define end of transient period at point when pointing error drops below 1 deg

k = find( pointingError*180/pi > 1 );
AnimateVectors(uTB(:,1:k(end)),'y');


%--------------------------------------
% PSS internal file version information
%--------------------------------------