Implements and simulates a spacecraft with reaction wheels and thrusters.

This script demonstrates:

The control system is designed for either Earth pointing or inertially fixed attitude. It does not allow attitude maneuvers. Thrusters can be used for attitude control. Thrusters are pulsewidth modulated and off-pulse for either east/west or north/south stationkeeping. The simulation also includes a single liquid apogee engine.

It is assumed that an IMU/Star tracker package is available that outputs a valid attitude quaternion in all modes.

Disturbance modeling is for solar pressure only.

The simulation propagates the orbit, the attitude and the reaction wheel rates. The reaction wheels are assume to take torque commands and produce that torque. That is to say they have a current feedback loop that compensates for back emf.

The controller is a simple PID controller in all modes.

The inertia matrix is for the deployed mode.

The wheels are Honeywell HR0610 wheels with 12 NMs max momentum at 6000 rpm. Max torque is 0.055 Nm.

The thrusters are EADS monopropellant thrusters: http://www.space-propulsion.com/spacecraft-propulsion/hydrazine-thrusters/1n-thruster.html

CHT 0.5 0.5 N (north, east west)
CHT 20 N (base panel)

The apogee engine is a 400 N "S400-12": http://www.space-propulsion.com/spacecraft-propulsion/apogee-motors/index.html

S400-12 420 N 318 sec

We put all properties into this script to make it self-contained. For more elaborate models they would be put in databases, etc.

------------------------------------------------------------------------
See also Inertias, PIDMIMO, QError, QLVLH, U2Q, Constant, Plot2D,
TimeGUI, TimeLabl, CosD, RK4, Date2JD, MassProp, El2RV, Period, SunV1,
ThrusterCommand, RHSRWA, ThreeAxisControlDisturb
------------------------------------------------------------------------

Contents

------------------------------------------------------------------------------ Copyright (c) 2007 Princeton Satellite Systems, Inc. All rights reserved. ------------------------------------------------------------------------------ 2017.1 Update function handles ------------------------------------------------------------------------------

Setup

% Clear variables used in this demo
%-----------------------------------
clear sc

% Global for the time interface
%------------------------------
global simulationAction
simulationAction = ' ';

Sim data

nSim  = 2000;
dT    = 0.25;
jD0   = Date2JD( [2010 3 15 0 0 0] );

% Control delta v demand. If any of pOn are non zero it will go into
% thruster mode
%-------------------------------------------------------------------
pOn   = 1*[ones(1,4) ones(1,13)];

% The thrusters to be used for ACS
%---------------------------------
kACS  = 1:12;

Spacecraft properties

%----------------------
width           =  2; % Each side is 2 meters
solarWingLength = 10; % A 10 kW satellite (assuming 20% efficient arrays)
solarWingBoom   =  1;
cM              = [0;0.01;0]; % A little offset to get a disturbance

sc.dist.areaArray  = 2*solarWingLength*width;
sc.dist.areaBox    = width^2;
sc.dist.cM         = cM;

% Surface properties [ absorbed specular diffuse transmitted ]
%-------------------------------------------------------------
sc.dist.sigmaArray = [ 0.75; 0.17; 0.08; 0.0 ]; % Solar panel
sc.dist.sigmaBox   = [ 0.0; 0.29; 0.71; 0.0 ]; % Gold foil

% Mass properties
%----------------
massArray          = solarWingLength*width*0.95; % 3 junction cells
massBox            = 1000;
inrArray           = Inertias( massArray, [width, solarWingLength], 'plate' );
inrBox             = Inertias( massBox,   [width width width],      'box');
cMArray            = [0;width/2 + solarWingBoom + solarWingLength/2;0];

inr                = [inrBox' inrArray' inrArray'];
m                  = [massBox massArray massArray];
cM                 = [[0;0;0] cMArray -cMArray];

[sc.inertia, sc.mass] = MassProp( inr, m, cM, 'mks' );

% Create the thruster unit vectors. This is the force direction
% [north west east base lae]
%--------------------------------------------------------------
%                      North       West        East       Base     LAE
%                   ----------  ---------- -----------  ----------  -
tc.uT           = [ 0  0  0  0  1  1  1  1 -1 -1 -1 -1  0  0  0  0  0;...
                    1  1  1  1  0  0  0  0  0  0  0  0  0  0  0  0  0;...
                    0  0  0  0  0  0  0  0  0  0  0  0  1  1  1  1  1];

tc.rT           = [ 1  1 -1 -1 -1 -1 -1 -1  1  1  1  1  1  1 -1 -1  0;...
                   -1 -1 -1 -1  1  1 -1 -1  1  1 -1 -1  1 -1  1 -1  0;...
                    1 -1  1 -1  1 -1  1 -1  1 -1  1 -1 -1 -1 -1 -1 -1]*width/2;

tc.thrust       = [ones(1,12)*0.5 ones(1,4)*20 420];

sc.inrWheel     = 12/(6000*pi/30); % HR 610
sc.mu           = Constant('mu earth');
c45             = CosD(45);
sc.uWheel       = c45*[1 0 -1 0; -1 -1 -1 -1; 0 1 0 -1];
sc.tDist        = [0.0001;0.0001;-0.0001]; % Just to see the transient response
sc.funDist      = @ThreeAxisControlDisturb;

Design the controller

%----------------------
[a,b,c,d] = PIDMIMO( 1, 1, 0.05, 200, 0.5, dT );

% PID States
%-----------
xX = zeros(2,1);
xY = zeros(2,1);
xZ = zeros(2,1);

% Controller output
%------------------
u  = zeros(3,1);

Select the orbital elements

[a i W w e M]

%----------------------------
el = [42167 0 0 0 0 0];
[r, v]      = El2RV( el );

Select the initial attitude

%--------------------------------
attitude = 'LVLH'; % or burn unit vector

% If attiude is a character align with LVLH, else align +z (the LAE thrust
% direction with the vector attitude
%-------------------------------------------------------------------------
if( ischar( attitude ) )
  qC   = QLVLH( r, v );
  w    = [0;-2*pi/Period(el(1));0];
  mode = 1;
else
  qC   = U2Q( [0;0;1], attitude );
  w    = [0;0;0];
  mode = 2;
end

Four reaction wheels

%---------------------
wRWA = [0;0;0;0];
q    = qC;

Put the state together

%-----------------------
x    = [r;v;q;w;wRWA];

Initialize the time display

%----------------------------
[ratioRealTime, tToGoMem] =  TimeGUI( nSim, 0, [], 0, dT, 'Three axis demo' );

Allocate memory for plotting array

%-----------------------------------
xPlot = zeros(27,nSim);
uTC   = zeros(length(kACS),nSim);

Run the simulation

------------------

for k = 1:nSim

  % Display the status message
  %---------------------------
  [ ratioRealTime, tToGoMem ] = TimeGUI( nSim, k, tToGoMem, ratioRealTime, dT );

  % Break up the state vector for convenience
  %------------------------------------------
  r = x(1:3); v = x(4:6); q = x(7:10);

  % Julian date
  %------------
  jD = jD0 + (k-1)*dT/86400;

  % Sun vector
  %-----------
  sc.dist.uSun = SunV1( jD );

  % The controller
  %---------------
  if( mode == 1 )
    qC = QLVLH( r, v );
  end

  % The attitude error
  %-------------------
  theta = QError( qC, q, 1 );

  % The control
  %------------
  u     = [c*xX + d*theta(1);...
           c*xY + d*theta(2);...
           c*xZ + d*theta(3)];

  % Convert angular accelerations to torque
  %----------------------------------------
  tDemand   = sc.inertia*u;

  % Either use thrusters or reaction wheels
  % Note the torque demand sign switch!
  %----------------------------------------
  if( max(pOn) > 0 )
    tDemand        = -tDemand;
    [sc.dist.force, sc.dist.torque, uu] = ThrusterCommand( tDemand, pOn, kACS, tc );
    sc.tRWA        = zeros(4,1);
    uTC(:,k)       = uu;
  else
    sc.dist.force  = zeros(3,1);
    sc.dist.torque = zeros(3,1);
    sc.tRWA        = pinv(sc.uWheel)*tDemand;
  end

  % Propagate the controller state. There is no limiter applied
  %------------------------------------------------------------
  xX    = a*xX + b*theta(1);
  xY    = a*xY + b*theta(2);
  xZ    = a*xZ + b*theta(3);

  % Store for plotting
  %-------------------
  xPlot(:,k) = [x;theta;sc.tRWA;tDemand];

  % Integrate one step
  %-------------------
  x          = RK4(@RHSRWA, x, dT, 0, sc );

  % Sim control from the time gui
  %------------------------------
  switch simulationAction
    case 'pause'
      pause
      simulationAction = ' ';
    case 'stop'
      return;
    case 'plot'
      break;
  end

end

Close the time gui

%-------------------
TimeGUI( 'close' );

Adjust the arrays if you quit early

%------------------------------------
j           = 1:k;
xPlot       = xPlot(:,j);
[tPlot, g ] = TimeLabl( (j-1)*dT );

Plot

%-----
Plot2D( tPlot, xPlot( 1: 3,:),        g, ['R_x (km)';'R_y (km)';'R_z (km)'],                   'Position'             )
Plot2D( tPlot, xPlot( 4: 6,:),        g, ['V_x (km/s)';'V_y (km/s)';'V_z (km/s)'],             'Velocity'             )
Plot2D( tPlot, xPlot( 7:10,:),        g, ['q_s';'q_x';'q_y';'q_z'],                            'Quaternion'           )
Plot2D( tPlot, xPlot(11:13,:),        g, ['\omega_x';'\omega_y';'\omega_z'],                   'Body Rates'           )
Plot2D( tPlot, xPlot(14:17,:),        g, ['\Omega_1';'\Omega_2';'\Omega_3';'\Omega_4'],        'Reaction Wheel Rates' )
Plot2D( tPlot, xPlot(18:20,:)*180/pi, g, ['\theta_x (deg)';'\theta_y (deg)';'\theta_z (deg)'], 'Attitude Errors'      )
Plot2D( tPlot, xPlot(21:24,:),        g, ['t_1 (Nm)';'t_2 (Nm)';'t_3 (Nm)';'t_4 (Nm)'],        'Wheel Control Demand' )
Plot2D( tPlot, xPlot(25:27,:),        g, ['t_x (Nm)';'t_y (Nm)';'t_z (Nm)'],                   'Control Demand'       )
if( max(pOn) > 0 )
  Plot2D( tPlot, uTC, g, 'Thrusters', 'Thruster Time Fractions' );
end
Figui


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