Contents

Design a manufacturing space station

Large space station with a Hall thruster for stationkeeping, hydrazine RCS thrusters, and a robot arm. There is an option for the solar arrays in the model to be deployed or not. This script creates both a full model and a simpler model for disturbance analysis. Both the full model, the thruster layout, and the simple model will be displayed in figures.

If file saving is turned on, this script saves the following:

- ManufacturingSpaceStation.mat, the CAD model data structure
- ManufacturingSpaceStation.tex, a latex table
- either the file SpaceStationProps.mat or SpaceStationPropsUndeployed.mat
  with the simplified surface model and thruster layout data
- SpaceStationThruster.txt, the thruster layout data

It will also export ManufacturingSpaceStation.obj as this is needed by the thruster layout step.

See also AtmDens2, BuildCADModel, CreateBody, CreateComponent, ExportOBJ, ThrusterCAD, XenonTank, VOrbit, HallThrusterArray, ThrusterLayout, Box, Frustrum, DisplayLatexTable, SaveStructure, DrawVertices, PolygonProps, DrawCanadarm3

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

% Script control
deployed   = true;
saveFiles  = false;

% Constants
rhoAl    = 2700;
rhoGlass = 2500;
rhoXe    = 3100; % km/m^2
rhoTi    = 4502; % kg/m^3
rE       = 6378.165;
tRefuel  = 5*365.25*24*3600; % 5 years
sigTi    = 0.5*880e6; % N/m^2 with a factor of safety of 2
effHall  = 0.6;
uEHall   = 20000; % m/s
massREA  = 0.3;
massHyd  = 200;
pHyd     = 350*6895;
rhoHyd   = 1000;

Properties

% Orbit
h  = 350; % km
cD = 2.7;

% Tank
pTank = 350*6895;

% Manufacturing modules
nModules    = 6;
rModule     = 1.0; % m
lModule     = 1.2*ones(1,6);  % m
massModule  = 500*ones(1,6);
useModule   = [1 1 1 1 1 1];

% Bus
lBus        = 2*lModule(1);  % m
massBus     = 2000;

% Rail for the robot arm
xRail       = sum(lModule(1:6));
yRail       = 0.1;
zRail       = 0.1;
massRail    = xRail*yRail*zRail*rhoAl*0.1;

% Keel
xKeel       = sum(lModule(1:6));
yKeel       = 0.2;
zKeel       = 0.2;
massKeel    = xKeel*yKeel*zKeel*rhoAl*0.1;

% Solar Panels
power     = 20000;
eff       = 0.31;
areaSP    = power/(eff*1367)/2;
wSP       = 2*rModule;
lSP       = areaSP/wSP;
tSP       = 0.04;
lStrut    = rModule;
massPanel = wSP*tSP*lSP*rhoGlass;
massStrut = lStrut*tSP^2*rhoAl;

% Hall Thruster
massHallThruster       = 3;
wHallThruster          = 0.5;
rHallThrusterGimbal    = 0.25*wHallThruster;
lHallThrusterGimbal    = 0.5*wHallThruster;
massHallThrusterGimbal = 0.75;

% Fuel Tank
r         = rE + h;
v         = VOrbit(r,r)*1000;
fHall     = 0.5*AtmDens2(h)*cD*v^2*(areaSP+4*rModule^2);
powerHall = 0.5*fHall*uEHall/effHall;

massXe   = fHall*tRefuel/uEHall;
volXe    = massXe/rhoXe;
rXeTank  = (0.75*volXe/pi)^(1/3);
tWall    = pTank*rXeTank/(2*sigTi);
massTank = tWall*4*pi*rXeTank^2;

% Robot arm
rLink    = 0.2; % m
lLink    = 2; % m
nLinks   = 3; % m
tLink    = 0.002; % Thickness of link strut m
angY     = [0 0 pi/4 pi/4]; % Just for the picture
massLink = tLink*2*pi*rLink*lLink*rhoAl;
xRobotArm = 2.2*lModule(1);

Initialize BuildCADModel and create the Core body

BuildCADModel( 'initialize' );
BuildCADModel( 'set name' , 'Manufacturing Space Station' );
BuildCADModel( 'set units', 'mks' );

% Core
m = CreateBody('make','name','Core');
BuildCADModel('add body', m );

% This creates the connections between the bodies
BuildCADModel( 'compute paths' );

% Modules
rA = [0;0;0];
for k = 1:nModules
  if( useModule(k))
    name = sprintf('Module %d',k);
    m = CreateComponent( 'make', 'cylinder', 'rUpper', rModule, 'rLower',rModule,'h',lModule(k),...
                     'n',20,'faceColor', 'gold foil','rA', rA,'b',[0 0 1;0 1 0;-1 0 0],...
                     'mass', massModule(k), 'name', name, 'body', 1, 'inside', 0 );
    BuildCADModel( 'add component', m );
  end
  rA(1) = rA(1) + lModule(k);
end

rA(1) = rA(1) + lBus/2;
rABus = rA;
m = CreateComponent( 'make', 'box', 'x', lBus, 'y',2*rModule,'z',2*rModule,...
                     'faceColor', 'Steel','rA', rABus,...
                     'mass', massBus, 'name', 'Bus', 'body', 1, 'inside', 0 );
BuildCADModel( 'add component', m );


% Add the keel and lateral supports
rA = [sum(lModule(1:3));0;-rModule-zKeel/2];
m = CreateComponent( 'make', 'box', 'x', xKeel, 'y',yKeel,'z',zKeel,...
                     'faceColor', 'aluminum','rA', rA,...
                     'mass', massKeel, 'name', 'Keel', 'body', 1, 'inside', 0 );
BuildCADModel( 'add component', m );

rA = [sum(lModule(1:3));-rModule-zKeel/2;0];
m = CreateComponent( 'make', 'box', 'x', xKeel, 'y',yKeel,'z',zKeel,...
                     'faceColor', 'aluminum','rA', rA,...
                     'mass', massKeel, 'name', 'Lateral 1', 'body', 1, 'inside', 0 );
BuildCADModel( 'add component', m );

rA = [sum(lModule(1:3));rModule+zKeel/2;0];
m = CreateComponent( 'make', 'box', 'x', xKeel, 'y',yKeel,'z',zKeel,...
                     'faceColor', 'aluminum','rA', rA,...
                     'mass', massKeel, 'name', 'Lateral 2', 'body', 1, 'inside', 0 );
BuildCADModel( 'add component', m );

%  Module supports
rA = [lModule(1)/2-lModule(1)/12;0;0];
rI = rModule;
rO = 1.01*rModule;
lS = lModule(1)/6;
massSupport = rhoAl*pi*(rO^2-rI^2)*lS;
for k = 1:6
  [v,f] = PartialThickDisk(rI,rO,lS,12,-pi/2,pi/2);
  s     = sprintf('Module Support %d',k);
  m = CreateComponent( 'make', 'generic', 'vertex',v, 'face',f,...
                     'faceColor', 'steel','rA', rA,'b',[0 0 1;0 1 0;-1 0 0],...
                     'mass', massSupport, 'name', s, 'body', 1, 'inside', 0 );
  BuildCADModel( 'add component', m );
  rA(1) = rA(1)+lModule(1);
end

% Solar panels and support struts
if( deployed )
  signY = 1;
  for k = 1:2
    nameP = sprintf('Solar Panel %d',k);
    rAW = [sum(lModule(1:6))+lBus/2;signY*(rModule+lStrut+lSP/2);0];
    m = CreateComponent( 'make', 'box', 'x', tSP, 'y',lSP,'z',wSP,...
                         'faceColor', 'solar cell','rA', rAW,...
                          'mass', massPanel, 'name', nameP, 'body', 1, 'inside', 0 );
    BuildCADModel( 'add component', m );

    nameS = sprintf('Solar Panel Strut %d',k);

    rAW(2) = signY*(rModule+lStrut/2);
    m = CreateComponent( 'make', 'box', 'x', tSP, 'y',lStrut,'z',tSP,...
                     'faceColor', 'aluminum','rA', rAW,...
                     'mass', massStrut, 'name', nameS, 'body', 1, 'inside', 0 );
    BuildCADModel( 'add component', m );
    signY = -signY;
  end
else
  signY = 1;
  for k = 1:2
    nameP = sprintf('Solar Panel %d',k);
    rA = rABus + [-lSP/2;signY*(rModule);0];
    lSPD = 0.5*lSP;
    m = CreateComponent( 'make', 'box', 'x',lSPD, 'y', tSP,'z',wSP,...
                         'faceColor', 'solar cell','rA', rA,...
                          'mass', massPanel, 'name', nameP, 'body', 1, 'inside', 0 );
    BuildCADModel( 'add component', m );

    nameS = sprintf('Solar Panel Strut %d',k);

    rA  = rA + [lSP/2;-signY*(rModule);0];
    m = CreateComponent( 'make', 'box', 'x',lStrut, 'y',tSP,'z',tSP,...
                     'faceColor', 'aluminum','rA', rA,...
                     'mass', massStrut, 'name', nameS, 'body', 1, 'inside', 0 );
    BuildCADModel( 'add component', m );
    signY = -signY;
  end

end

% Hall Thruster
[v, f] = HallThrusterArray( wHallThruster );
rA     = [sum(lModule)+2*rHallThrusterGimbal+lBus;0;0];
b      = [0 0 1;0 1 0;-1 0 0];
m = CreateComponent( 'make', 'generic', 'vertex',v, 'face',f,...
                     'faceColor', 'steel','rA', rA,'b',b,...
                     'mass', massHallThruster, 'name', 'Hall Thruster', 'body', 1, 'inside', 0 );
BuildCADModel( 'add component', m );
rA     = [sum(lModule)+2*rHallThrusterGimbal+lBus;0;-lHallThrusterGimbal/2];
rA     = rA -[rHallThrusterGimbal;0;0];
m = CreateComponent( 'make', 'cylinder', 'rUpper',rHallThrusterGimbal, 'rLower',rHallThrusterGimbal,'h',lHallThrusterGimbal,...
                     'faceColor', 'steel','rA', rA,...
                     'mass', massHallThrusterGimbal, 'name', 'Hall Thruster Gimbal', 'body', 1, 'inside', 0 );
BuildCADModel( 'add component', m );

[v,f,dTank] = XenonTank(massXe);
rA = [sum(lModule)+2*rHallThrusterGimbal+lBus;0;0] - [1;0;0.8];
m = CreateComponent( 'make', 'generic', 'vertex',v, 'face',f,...
                     'faceColor', 'steel','rA', rA,...
                     'mass', massXe+dTank.massTank, 'name', 'Xenon tank', 'body', 1, 'inside', 1 );
BuildCADModel( 'add component', m );

d      = DrawCanadarm3( 'initialize' );
x      = zeros(7,1);
[v,f]  = DrawCanadarm3( 'vectors', x, d );

m = CreateComponent( 'make', 'generic', 'vertex',v, 'face',f,...
                     'faceColor', 'steel','rA', rA,...
                     'mass', 100, 'name', 'Robot Arm', 'body', 1, 'inside', 1 );
BuildCADModel( 'add component', m );

% RCS hydrazine thrusters
lThruster     = 0.026;
dConeThruster = 0.02;
r             = rModule;
x             = lBus/2;

rThruster     = rABus + [x  x -x -x x  x  x  x;...
                         r -r  r -r r  r -r -r;...
                         r  r  r  r r -r  r -r];
uThruster     =  [ 0 0 0 0 1 1 1 1;....
                   0 0 0 0 0 0 0 0;....
                   1 1 1 1 0 0 0 0];
for k = 1:8
  [v, f]  = ThrusterCAD( uThruster(:,k), dConeThruster, lThruster, 12, 0.7*dConeThruster,lThruster );
  s       = sprintf('Thruster %d',k);
  m       = CreateComponent( 'make', 'generic', 'v', v, 'f', f, 'faceColor', [0 0.5 0.5],...
                       'rA',  rThruster(:,k), 'mass', massREA , 'name', s, 'body', 1, 'inside', 0 );
  BuildCADModel( 'add component', m );
end

% Hydrazine tank

vol  = massHyd/rhoHyd;
rHyd = (0.75*vol/pi)^(1/3);
m = CreateComponent( 'make', 'sphere', 'radius',rHyd,...
                     'faceColor', 'steel','rA', rABus,...
                     'mass', massHyd+massTank, 'name', 'Hydrazine tank', 'body', 1, 'inside', 1 );
BuildCADModel( 'add component', m );

Add subsystems

BuildCADModel( 'add subsystem', 'TT&C',	      {'avionics', 'imu', 'star camera'} );
BuildCADModel( 'add subsystem', 'Power',      {'battery' 'Solar'} );
BuildCADModel( 'add subsystem', 'Robot arm',  {'link' 'rail'} );
BuildCADModel( 'add subsystem', 'Propulsion', {'tank','thruster' 'gimbal'} );
BuildCADModel( 'add subsystem', 'Structure',  {'module' 'bus' 'keel'} );

Update the mass properties to produce the tables

BuildCADModel( 'update body mass properties' );

Show the vehicle and save the components

g = BuildCADModel( 'get model' );
BuildCADModel('show vehicle');

if saveFiles
  SaveStructure(g,'ManufacturingSpaceStation');
end

Export to an obj file for use by other software

ExportOBJ(g,'ManufacturingSpaceStation');

inr = diag(g.mass.inertia)';
inrC1 = LatexExp(inr(1),'8.2');
inrC2 = LatexExp(inr(2),'8.2');
inrC3 = LatexExp(inr(3),'8.2');
s = {};
k = 1;
s{k,1} = 'Power';                    s{k,2} = sprintf('%8.2f W',power); k = k + 1;
s{k,1} = 'Orbit Altitude';           s{k,2} = sprintf('%8.2f km',h); k = k + 1;
s{k,1} = 'Mass';                     s{k,2} = sprintf('%8.2f kg',g.mass.mass); k = k + 1;
s{k,1} = '[$I_{xx}~I_{yy}~I_{zz}$]'; s{k,2} = sprintf('[%s %s %s] kg-m$^2$',inrC1,inrC2,inrC3); k = k + 1;
s{k,1} = 'Center of Mass';           s{k,2} = sprintf('%8.2f %8.2f %8.2f m',g.mass.cM); k = k + 1;
s{k,1} = 'Mass Xenon';               s{k,2} = sprintf('%8.2f kg',massXe); k = k + 1;
s{k,1} = 'Hall Thruster thrust';     s{k,2} = sprintf('%8.2f mN',fHall*1000); k = k + 1;
s{k,1} = 'Hall Thruster power';      s{k,2} = sprintf('%8.2f kW',powerHall/1000);
DisplayLatexTable(s)
if saveFiles
  CreateLatexTable(s,'ManufacturingSpaceStation'); % to save file
end
                   Power                                                                20000.00 W 
          Orbit Altitude                                                                 350.00 km 
                    Mass                                                               10641.71 kg 
[$I_{xx}~I_{yy}~I_{zz}$] [3.54 $\times 10^{5}$ 7.33 $\times 10^{4}$ 4.21 $\times 10^{5}$] kg-m$^2$ 
          Center of Mass                                                  6.86    -0.00    -0.03 m 
              Mass Xenon                                                                 159.47 kg 
    Hall Thruster thrust                                                                  20.21 mN 
     Hall Thruster power                                                                   0.34 kW 

Compute the thruster torque distribution

ThrusterLayout( 'initialize', 'ManufacturingSpaceStation.obj' );

[t,f,u] = ThrusterLayout( 'update', -uThruster, rThruster, g.mass.cM );
fprintf(1,'\nFeasible = 1 means the torque can be achieved\n');
b = [1 -1 0 0 0 0;0 0 1 -1 0 0; 0 0 0 0 1 -1];
for k = 1:6
	fprintf(1,'Torque demand = [%4.1f %4.1f %4.1f] u = [%4.2f %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f] Feasible = %d\n',b(:,k),u(:,k),f(k));
end

if saveFiles
  fThruster = fopen('SpaceStationThruster.txt','wt');
  for k = 1:size(uThruster,2)
    fprintf(fThruster,'%8.4f %8.4f %8.4f %8.4f %8.4f %8.4f\n',rThruster,uThruster);
  end
  fclose(fThruster);
end

mass = g.mass;
Feasible = 1 means the torque can be achieved
Torque demand = [ 1.0  0.0  0.0] u = [0.00 0.00 0.00 1.00 0.17 0.00 0.17 0.00] Feasible = 1
Torque demand = [-1.0  0.0  0.0] u = [0.00 0.00 1.00 0.00 0.17 0.00 0.17 0.00] Feasible = 1
Torque demand = [ 0.0  1.0  0.0] u = [0.18 0.18 0.00 0.00 0.00 0.00 0.00 0.00] Feasible = 1
Torque demand = [ 0.0 -1.0  0.0] u = [0.00 0.00 0.00 0.00 0.49 0.00 0.49 0.00] Feasible = 1
Torque demand = [ 0.0  0.0  1.0] u = [0.00 0.00 0.00 0.00 0.49 0.51 0.00 0.00] Feasible = 1
Torque demand = [ 0.0  0.0 -1.0] u = [0.00 0.00 0.00 0.00 0.00 0.00 0.49 0.51] Feasible = 1

Make a simple CAD Model for disturbance analyses

[v,f]     = Frustrum(rModule,rModule,sum(lModule),8);
v         = ([0 0 1;0 1 0;-1 0 0]*v')';
[vB,fB]   = Box(lBus,2*rModule,2*rModule);
vB(:,1)   = vB(:,1) + sum(lModule)+lBus/2;
f         = [f;fB+size(v,1)];
v         = [v;vB];

% Solar wings
rAW         = [sum(lModule(1:6))+lBus/2;rModule+lStrut+lSP/2;0];
[vW,fW]     = Box(tSP, lSP,wSP);
vW          = vW + rAW';

rAW         = [sum(lModule(1:6))+lBus/2;-rModule-lStrut-lSP/2;0];
[vW2,fW2]   = Box(tSP, lSP,wSP);
vW2         = vW2 + rAW';

fW          = [fW;fW2+size(vW,1)];
vW          = [vW;vW2];

[a,n,r]     = PolygonProps(v,f);
[aW,nW,rW]  = PolygonProps(vW,fW);
dSurf       = struct('aB',a,'nB',n,'rB',r,'aW',aW,'nW',nW,'rW',rW);

% Combine to draw
f           = [f;fW+size(v,1)];
v           = [v;vW];

DrawVertices(v,f,'Simple Model');

Save the data for the simulation

if saveFiles
  if( deployed )
    save('SpaceStationProps','mass', 'rThruster','uThruster','dSurf')
  else
    save('SpaceStationPropsUndeployed','mass', 'rThruster','uThruster','dSurf')
  end
end

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

% $Id: 33eaaa03a2abd39c37fa5fb0510bdc7d6121c823 $