An attitude and orbit simulation with reaction wheels.

This simulation includes reaction wheels with Coulomb friction and damping. It is easy to specify the damping terms for each wheel. The demo also includes the PID3Axis controller. The core dynamics is for a gyrostat orbiting around a point mass.

The simulation uses the vector pointing mode of PID3Axis to point a vector in the spacecraft frame either at nadir or at the sun.

Control logic is included to point at nadir when the spacecraft is over the continental United States and at the sun otherwise.

------------------------------------------------------------------------
See also RHSSpacecraftWithRWA, PID3Axis, Plot2D, RK4
------------------------------------------------------------------------

Contents

%--------------------------------------------------------------------------
%   Copyright (c) 2017 Princeton Satellite Systems, Inc.
%   All rights reserved.
%--------------------------------------------------------------------------
%   Since version 2017.1
%--------------------------------------------------------------------------

Initialization

The RHS provides the default data structure for the model. Three orthogonal wheels are assumed. The default friction is zero for each wheel.

% Earth's radius
rE   = 6378.165;

% Simulation timing
tEnd = 10000.0; % sec
dT   = 1.0; % sec

% Initial Julian Date
jD0  = Date2JD([2020 4 5 0 0 0]);

% Spacecraft altitude
h         = 600.0; % km

% Data structure for the right hand side.
% Note non-spherical inertia matrix which results in cross-axis coupling.
d         = RHSSpacecraftWithRWA;
d.inr     = [3 0 0;0 10 0;0 0 5]; % kg-m^2
% Wheel inertia
d.inrRWA  = 1.5e-3*[1;1;1];  % kg-m^2

% Friction damping terms
% cDamping (viscous damping) should be on the order of 1e-6 Nms
% torqueCoulomb should be on the order of 1e-3 Nm
d.friction.cDampingRWA      = [5;5;5]*1e-6;      % Nms
d.friction.torqueCoulombRWA = [1;1;1]*1e-3;   % Nm

% Disturbance torque, Nm; try about 1-10e-5 Nm
d.torque = [0.0;0.0;0.0];

% Initial body rates, rad/s; try about 0.001 rad/s
wInit = [0.0;0;0.0];

% Initial wheel speeds
wRWA  = [0.0;0.0;0.0];

Design the controller

Use the PID3Axis function which handles updating the controller states.

dC                  = PID3Axis; % Gets the default data structure
dC.mode             = 1; % Vector tracking

% We specify a unit inertia so that the controller generates a control
% angular acceleration
inr   = 1.0;   % unit inertia
zeta  = 1.0;   % damping ratio
omega = 0.03;  % rad/sec
tauInt = 200;  % sec
omegaR = 0.05; % rad/sec
[dC.a, dC.b, dC.c, dC.d] = PIDMIMO(inr,zeta,omega,tauInt,omegaR,dT);
dC.body_vector  = [0;0;1];

Simulation

Perform a fixed step integration using RK4. The state vector includes the wheel speeds. The spacecraft is initialized in a circular orbit with zero rates.

% Steps
n         = ceil(tEnd/dT);

% State vector: [position;velocity;quaternion;body rate;rwa rate]
rInit     = (rE+h)*[cos(2);sin(2);0];
vInit     = [0;0;sqrt(d.mu/(rE+h))];
qInit     = [1;0;0;0];
x         = [rInit; vInit; qInit; wInit; wRWA];
rEF       = zeros(3,n);
xP        = zeros(length(x)+5,n);
t         = (0:n-1)*dT;
jD        = jD0 + t/86400;

% Create the area to be checked. Roughly covers CONUS.
m         = 100;
[lat,lon] = RAzToLatLon( 2000*ones(1,m), linspace(0,2*pi,m), pi/4, -1.1*pi/2 );

lat       = fliplr(lat);
lon       = fliplr(lon);
overA     = zeros(1,n);

for k = 1:n
  % Local variables
  r           = x( 1: 3);
  q           = x( 7:10);

  % ECI sun and Earth vectors
  bECIToEF    = EarthRot(JD2T(jD(k)));
  rEF(:,k)    = bECIToEF*r;

  j           = OverArea( rEF(:,k),lat,lon);
  if( j == 0 )
    dC.eci_vector = SunV1( jD(k));
  else
    dC.eci_vector = -Unit(r);
    overA(k) = 1;
	end

  % The PID controller
  [tRHS, dC]	= PID3Axis( q, dC );

  % Reaction wheel torque is on the left hand side
  d.torqueRWA = -d.inr*tRHS;

  % Pointing error
  arg         = dC.eci_vector'*QTForm( q, dC.body_vector );
  if( abs(arg) > 1 )
    arg = sign(arg);
  end
  pErr        = acos(arg);

  % Plot storage
  xP(:,k)     = [x;d.torqueRWA;j;pErr];

  % Right hand side
  x           = RK4(@RHSSpacecraftWithRWA,x,dT,0,d);
end

Plotting

[t,tL] = TimeLabl(t);

3D Plot

LoadEarthMap;
hold on
[~,rS] = OverArea( x(1:3), lat, lon );
plot3(rS(1,:),rS(2,:),rS(3,:),'color','r');
plot3(rEF(1,:),rEF(2,:),rEF(3,:),'color','y','linewidth',2);
kOver = find(overA>0);
plot3(rEF(1,kOver),rEF(2,kOver),rEF(3,kOver),'c.');

2D plots

Position

k      = [1:3 20:21];
yL     = {'r_x', 'r_y', 'r_z' 'Region' 'Error'};
h(1) = Plot2D( t, xP(k,:),tL,yL,'Position');
AddFillToPlots(t,overA,h(1),[1 1 1;0.8 0.8 0.8],0.5)

% Quaternion
k      = 7:10;
yL     = {'q_s', 'q_x', 'q_y', 'q_z'};
h(2) = Plot2D( t, xP(k,:),tL,yL,'Attitude');
AddFillToPlots(t,overA,h(2),[1 1 1;0.8 0.8 0.8],0.5)

% Angular rate
k      = 11:13;
yL     = {'\omega_x', '\omega_y', '\omega_z'};
h(3) = Plot2D( t, xP(k,:),tL,yL,'Body Rates');
AddFillToPlots(t,overA,h(3),[1 1 1;0.8 0.8 0.8],0.5)

% Reaction wheel torque and rate
k      = 17:19;
yL     = {'T_x (Nm)', 'T_y (Nm)', 'T_z (Nm)'};
h(4) = Plot2D( t, xP(k,:),tL,yL,'RWA Torque');
AddFillToPlots(t,overA,h(4),[1 1 1;0.8 0.8 0.8],0.5)

k      = 14:16;
yL     = {'\omega_1', '\omega_2', '\omega_3'};
h(5) = Plot2D( t, xP(k,:),tL,yL,'RWA Speeds');
AddFillToPlots(t,overA,h(5),[1 1 1;0.8 0.8 0.8],0.5)

Figui;


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