00001 /*! \page TutorialsPage Tutorials 00002 \ref TableOfContents : \ref IntroductionPage : \ref TutorialAnswersPage 00003 00004 The following sections are sets of tutorials meant to lead the user through the basics of using the Open-Sessame Framework 00005 all the way to creating a full spacecraft simulation application. Each section is a listing of a textual 00006 description of the problem to be solved, followed by a reference to the answer sheet. Don't cheat! Following the 00007 successful completion of each lesson, the user should move onto the next lesson until all the tutorials are complete. 00008 00009 \par Running Tutorials: 00010 To build and run a tutorial, (after writing your file, e.g. myFile.cpp) follow the following instructions: 00011 -# Put the @em .cpp file in the @em spacecraft/src/test directory: 00012 \verbatim cp myFile.cpp spacecraft/src/test 00013 cd spacecraft/src/test\endverbatim 00014 or use whatever method you choose for getting it there (ftp, sftp, scp, drag -n- drop, mv, etc.) 00015 -# Build the program by running the generalized makefile with the target of your source file, minus the @em cpp extension: 00016 \verbatim make myFile \endverbatim 00017 -# Run the program in the same directory (the executable will be the same as the source file minus the extension): 00018 \verbatim ./myFile \endverbatim 00019 -# Debug the code (unless your implementation was perfect, then check your answers) 00020 - If you need help check the suggested \ref ProgrammingTroubleshooting 00021 00022 \section RotationTutorials Rotation Tutorials 00023 -# Create a Quaternion that has the initial parameters (0.5,0.5,0.5,0.5). 00024 -# Output this quaternion to the console in both quaternion and Modified Rodriguez Parameters (MRP) form. 00025 -# Create a Direction Cosine Matrix corresponding to a 321 rotation with angles: 10, -30, 150 degrees. 00026 -# Create 2 "Rotation"s that are intialized by the quaternion and Direction Cosine Matrix. 00027 -# Determine the successive rotation of these two rotations and output to the console in DCM form. 00028 -# Verify that the answer you got was the correct (expected) one. 00029 00030 \ref TutorialAnswersPage 00031 00032 \section UtilityTutorials Utility Tutorials 00033 -# Create an ssfTime object, set the epoch to the current real time, and the stored 'current' time to 50 seconds later. Output both of these in DateTime and JulianDate format to the console. 00034 -# Plot a Matrix of values corresponding to the \f$ f(x)=\sin{x}\f$ for \f$x=0:2\pi \f$ using the Open-Sessame GnuPlot interface. 00035 -# Create a linear interpolation of the \f$\sin{}\f$ function using a step-size of 0.1 00036 00037 \ref TutorialAnswersPage 00038 00039 \section AttitudeTutorials Attitude Tutorials 00040 -# Create an AttitudeState object instance that is initialized to an aligned rotation in the Orbit-Inertial Frame (attitudeframe not yet implemented fully). 00041 -# Integrate an attitude for 50 seconds using the following conditions: 00042 - Quaternion Kinematics 00043 - Euler's equations of motion 00044 - Gravity-gradient torque disturbance 00045 - Initial conditions of: \f$\bar{\bf q}_0 = [0,0,0,1]^{T}\f$ and \f$\omega_{0} = [0,0.1, -0.05]^{T} \frac{rad}{s}\f$. 00046 - Principle Moments of Inertia: \f$[100, 300, 150]\f$ 00047 -# Store the attitude to a text file. 00048 -# Plot the attitude history using GnuPlot. 00049 -# Store the attitude in DirectionCosineMatrix format in a MatLab file. 00050 00051 \ref AttitudeTutorialAnswer 00052 00053 \section OrbitTutorials Orbit Tutorials 00054 -# Create an OrbitState object instance that is initialized to the current state of the spacestation in inertial coordinates. 00055 -# Convert to ECEF coordinates and output to the console. 00056 -# Integrate an orbit for 2 orbits using the following conditions: 00057 - 2-body force function above the Earth (mass = 200 kg). 00058 - Solar-radiation pressure force disturbance (assume constant \f$Area=20 m^2\f$). 00059 - Initial conditions of: \f${\bf r}=[-5776.6, -157, 3496.9]^{T}\f$ (km) and \f${\bf v} = [-2.595, -5.651, -4.513]^{T}\f$ (km/s). 00060 -# Store the position and velocity to a text file. 00061 -# Plot the orbit position vector using GnuPlot. 00062 -# Store the orbit Keplerian parameters in a MatLab file. 00063 00064 \ref OrbitTutorialAnswer 00065 00066 \section CoupledTutorials Coupled Attitude & Orbit Tutorials 00067 -# Create an Environment object of the Earth using the above (Orbit \& Attitude) disturbance force \& torque functions. 00068 -# Create a Propagator that will propagate the above Orbit \& Attitude objects and using the Environment object. 00069 - Use a linear interpolator for the OrbitHistory. 00070 - Use loose coupling (orbit independent of attitude, but attitude dependent on position). 00071 -# Propagate the orbit and attitude for 2 orbits. 00072 -# Plot the position and attitude using gnuplot. 00073 -# Propagate another 2 orbits. 00074 -# Add the new states to the previously made plots. 00075 00076 \ref CoupledTutorialAnswer 00077 */ 00078 00079 /*! \page TutorialAnswersPage Tutorial Answers Page 00080 \ref TableOfContents : \ref IntroductionPage : \ref TutorialsPage 00081 00082 \section RotationTutorialAnswer Rotation Tutorial Answer 00083 00084 \code 00085 // Create a Quaternion that has the initial parameters (0.5,0.5,0.5,0.5). 00086 Quaternion myQuat(0.5, 0.5, 0.5, 0.5); 00087 00088 // Output this quaternion to the console in both quaternion and MRP form 00089 cout << myQuat; 00090 cout << myQuat.GetMRP(); 00091 00092 // Create a Direction Cosine Matrix corresponding to a 321 rotation with angles: 10, -30, 150 degrees. 00093 DirectionCosineMatrix myDCM(10*RPD, -30*RPD, 150*RPD, 321); 00094 00095 // Create 2 "Rotation"s that are intialized by the quaternion and Direction Cosine Matrix. 00096 Rotation myRot1(myQuat); 00097 Rotation myRot2(myDCM); 00098 00099 // Determine the successive rotation of these two rotations and output to the console in DCM form. 00100 cout << (myRot1 * myRot2).GetDCM(); 00101 00102 // Verify that the answer you got was the correct (expected) one. 00103 Matrix Answer(3,3); 00104 00105 \endcode 00106 00107 Back to: \ref RotationTutorials 00108 <hr> 00109 00110 \section UtilityTutorialAnswer Utility Tutorial Answer 00111 -# Create an ssfTime object, set the epoch to the current real time, and the stored 'current' time to 50 seconds later. Output both of these in DateTime and JulianDate format to the console. 00112 \code 00113 ssfTime myTime; 00114 myTime.SetEpoch(Now()); 00115 myTime.Set(myTime.GetEpoch() + 50); 00116 cout << myTime.GetDateTime().tm_mon << "/" << myTime.GetDateTime().tm_mday << "/" << myTime.GetDateTime().tm_year << endl; 00117 cout << myTime.GetJulianDate() << endl; 00118 \endcode 00119 00120 -# Plot a Matrix of values corresponding to the \f$ f(x)=\sin{x}\f$ for \f$x=0:2\pi \f$ using the Open-Sessame GnuPlot interface. 00121 \code 00122 int stepsize = 0.1; 00123 Matrix datavec(2*M_PI / stepsize,2); 00124 for (int jj = 1; jj <= datavec[MatrixRowsIndex].getIndexBound(); ++jj) 00125 { 00126 datavec(jj,1) = jj * stepsize; 00127 datavec(jj,2) = sin(jj * stepsize); 00128 } 00129 Plot2D(datavec); 00130 \endcode 00131 -# Create a linear interpolation of the \f$\sin{}\f$ function using a step-size of 0.1 00132 \code 00133 int stepsize = 0.1; 00134 Vector timeVec(2*M_PI / stepsize); 00135 Matrix dataMat(timeVec[MatrixRowsIndex].getIndexBound(), 1); 00136 for (int jj = 1; jj < timeVec[MatrixRowsIndex].getIndexBound(); ++jj) 00137 { 00138 timeVec(jj) = jj * stepsize; 00139 dataMat(jj,1) = sin(jj * stepsize); 00140 } 00141 00142 LinearInterpolator interp(timeVec,dataMat); 00143 Vector chk = interp.Evaluate(0.25); 00144 cout << timevec << endl << datavec << endl << sin(0.25) << " = " << chk << endl; 00145 \endcode 00146 Back to: \ref UtilityTutorials 00147 <hr> 00148 00149 \section AttitudeTutorialAnswer Attitude Tutorial Answer 00150 -# Create an AttitudeState object instance that is initialized to an aligned rotation in the Orbit-Inertial Frame (attitudeframe not yet implemented fully). 00151 \code 00152 AttitudeState myAttState(Rotation(), new AttitudeFrameOI); 00153 \endcode 00154 00155 -# Integrate an attitude for 50 seconds using the following conditions: 00156 00157 First setup the kinematics equation: 00158 \code 00159 static Vector AttituteDynamics(const ssfTime &_time, const Vector& _integratingState, Orbit *_pOrbit, Attitude *_pAttitude, const Matrix &_parameters, const Functor &_forceFunctorPtr) 00160 { 00161 // Initialize the vectors used in the calculation. 00162 // made static, which causes the memory to be allocated the first time the function is called 00163 // and then left in memory during the program to speed up computation. 00164 static Vector stateDot(7); 00165 static Matrix bMOI(3,3); 00166 static Matrix qtemp(4,3); 00167 static Matrix Tmoment(3,1); 00168 static Vector qIn(4); 00169 static Vector wIn(3); 00170 00171 // Retrieve the current integration states to a quaternion and angular velocity vector 00172 qIn = _integratingState(_(VectorIndexBase,VectorIndexBase + 3)); 00173 wIn = _integratingState(_(VectorIndexBase + 4,VectorIndexBase + 6)); 00174 qIn /= norm2(qIn); 00175 00176 // Calculate qDot 00177 qtemp(_(VectorIndexBase+0,VectorIndexBase+2),_(VectorIndexBase+0,VectorIndexBase+2)) = skew(qIn(_(VectorIndexBase+0,VectorIndexBase+2))) + qIn(VectorIndexBase+3) * eye(3); 00178 qtemp(VectorIndexBase+3, _(VectorIndexBase+0,VectorIndexBase+2)) = -(~qIn(_(VectorIndexBase+0,VectorIndexBase+2))); 00179 qtemp(_,MatrixIndexBase) = 0.5 * qtemp * wIn; 00180 00181 // Get the moments of inertia and calculate the omegaDot 00182 bMOI = _parameters(_(MatrixIndexBase+0,MatrixIndexBase+2),_(MatrixIndexBase+0,MatrixIndexBase+2)); 00183 Tmoment = (bMOI.inverse() * (Tmoment - skew(wIn) * (bMOI * wIn))); 00184 00185 // Combine the qDot and omegaDot into a stateDot vector 00186 stateDot(_(VectorIndexBase,VectorIndexBase + 3)) = qtemp(_,MatrixIndexBase); 00187 stateDot(_(VectorIndexBase + 4,VectorIndexBase + 6)) = Tmoment(_,MatrixIndexBase); 00188 00189 return stateDot; 00190 } 00191 \endcode 00192 00193 Then setup the driver code to run the above dynamics equation: 00194 \code 00195 // Setup an integrator and any special parameters 00196 RungeKuttaIntegrator myIntegrator; 00197 myIntegrator.SetNumSteps(1000); 00198 // Integration times 00199 vector<ssfTime> integrationTimes; 00200 ssfTime begin(0); 00201 ssfTime end(begin + 50); 00202 integrationTimes.push_back(begin); 00203 integrationTimes.push_back(end); 00204 00205 // Create the initial attitude state 00206 AttitudeState myAttitudeState; 00207 myAttitudeState.SetRotation(Rotation(Quaternion(0,0,0,1))); 00208 Vector initAngVelVector(3); 00209 initAngVelVector(1) = 0; 00210 initAngVelVector(2) = 0.1; 00211 initAngVelVector(2) = -0.5; 00212 myAttitudeState.SetAngularVelocity(initAngVelVector); 00213 SpecificFunctor AttitudeForcesFunctor(&NullFunctor); 00214 00215 // Create the matrix of parameters needed for the RHS - MOI 00216 Matrix Parameters = eye(3); 00217 Parameters(1) = 100; 00218 Parameters(2) = 300; 00219 Parameters(3) = 150; 00220 00221 // Integrate over the desired time interval 00222 Matrix history = myIntegrator.Integrate( 00223 integrationTimes, // seconds 00224 &AttituteDynamics, 00225 myAttitudeState.GetState(), 00226 NULL, 00227 NULL, 00228 Parameters, 00229 AttitudeForcesFunctor 00230 ); 00231 \endcode 00232 -# Store the attitude to a text file. 00233 \code 00234 ofstream ofile; 00235 ofile.open("AttitudeHistory.dat"); 00236 ofile << history; 00237 ofile.close(); 00238 \endcode 00239 00240 -# Plot the attitude history using GnuPlot. 00241 \code 00242 Matrix plotting = history(_,_(MatrixIndexBase,MatrixIndexBase+4)); 00243 Plot2D(plotting); 00244 \endcode 00245 00246 -# Store the attitude in DirectionCosineMatrix format in a MatLab file. 00247 00248 Back to: \ref AttitudeTutorials 00249 <hr> 00250 00251 \section OrbitTutorialAnswer Orbit Tutorial Answer 00252 Setup the dynamic equations: 00253 \code 00254 static Vector TwoBodyDynamics(const ssfTime &_time, const Vector& _integratingState, Orbit *_Orbit, Attitude *_Attitude, const Matrix &_parameters, const Functor &_forceFunctorPtr) 00255 { 00256 static Vector Forces(3); 00257 static Vector Velocity(3); 00258 static Vector stateDot(6); 00259 static AttitudeState tempAttState; // don't need this except to pass an empty one if there is no attitude 00260 static OrbitState orbState(new PositionVelocity); 00261 00262 orbState.GetStateRepresentation()->SetPositionVelocity(_integratingState); 00263 00264 if(_Attitude) 00265 Forces = _forceFunctorPtr.Call(_time, orbState, _Attitude->GetStateObject()); 00266 else 00267 Forces = _forceFunctorPtr.Call(_time, orbState, tempAttState); 00268 00269 Velocity(_) = _integratingState(_(VectorIndexBase+3,VectorIndexBase+5)); 00270 00271 00272 stateDot(_(VectorIndexBase, VectorIndexBase+2)) = Velocity(_); 00273 stateDot(_(VectorIndexBase+3, VectorIndexBase+5)) = Forces(_); 00274 return stateDot; 00275 } 00276 \endcode 00277 The force functions are setup as follows (using drag instead of solar radiation pressure): 00278 \code 00279 Vector OrbitForcesWithDragFunctor(const ssfTime& _pSSFTime, const OrbitState& _pOrbitState, const AttitudeState& _pAttitudeState) 00280 { 00281 Vector Forces; 00282 Vector Position(3); Position(_) = _pOrbitState.GetStateRepresentation()->GetPositionVelocity()(_(VectorIndexBase,VectorIndexBase+2)); 00283 00284 double BC = 0.5; 00285 Vector Vrel(3); Vrel = _pOrbitState.GetStateRepresentation()->GetPositionVelocity()(_(VectorIndexBase+3,VectorIndexBase+5)); 00286 double Vrel_mag = norm2(Vrel); 00287 Forces = -398600.4418 / pow(norm2(Position),3) * Position; 00288 00289 Forces += -1/2 *1/BC * pow(Vrel_mag,2) * Vrel / Vrel_mag; 00290 return Forces; 00291 } 00292 \endcode 00293 00294 Finally create the driver program and call the integration: 00295 \code 00296 // Setup an integrator and any special parameters 00297 RungeKuttaIntegrator myIntegrator; 00298 int numOrbits = 2; 00299 int numSteps = 100; 00300 myIntegrator.SetNumSteps(numSteps); 00301 00302 vector<ssfTime> integrationTimes; 00303 ssfTime begin(0); 00304 ssfTime end(begin + 92*60*numOrbits); 00305 integrationTimes.push_back(begin); 00306 integrationTimes.push_back(end); 00307 00308 OrbitState myOrbitState; 00309 myOrbitState.SetStateRepresentation(new PositionVelocity); 00310 myOrbitState.SetOrbitFrame(new OrbitFrameIJK); 00311 Vector initPV(6); 00312 initPV(VectorIndexBase+0) = -5776.6; // km/s 00313 initPV(VectorIndexBase+1) = -157; // km/s 00314 initPV(VectorIndexBase+2) = 3496.9; // km/s 00315 initPV(VectorIndexBase+3) = -2.595; // km/s 00316 initPV(VectorIndexBase+4) = -5.651; // km/s 00317 initPV(VectorIndexBase+5) = -4.513; // km/s 00318 myOrbitState.GetStateRepresentation()->SetPositionVelocity(initPV); 00319 00320 Matrix history = myIntegrator.Integrate( 00321 integrationTimes, // seconds 00322 &TwoBodyDynamics, 00323 myOrbit.GetStateRepresentation()->GetPositionVelocity(), 00324 NULL, 00325 NULL, 00326 Parameters, 00327 OrbitForcesFunctor 00328 ); 00329 \endcode 00330 00331 -# Store the position and velocity to a text file. 00332 \code 00333 ofstream ofile; 00334 ofile.open("OrbitHistory.dat"); 00335 ofile << history; 00336 ofile.close(); 00337 \endcode 00338 00339 -# Plot the orbit position vector using GnuPlot. 00340 \code 00341 // Create the plot using Columns 2:4 00342 Matrix orbitHistory = myOrbit->GetHistory().GetHistory(); 00343 Matrix orbitPlotting = orbitHistory(_,_(2,4)); 00344 Plot3D(orbitPlotting); 00345 \endcode 00346 Here is a check for your answer (without solar radiation pressure): 00347 \verbatim 00348 [ time, r1, r2, r3, v1, v2, v3] 00349 [ 5400, -5386.654, 562.845, 4034.074, -3.518027, -5.617977, -3.890888 ] 00350 \endverbatim 00351 00352 -# Store the orbit Keplerian parameters in a MatLab file. 00353 00354 Back to: \ref OrbitTutorials 00355 00356 \section CoupledTutorialAnswer Coupled Tutorial Answers 00357 -# Create an Environment object of the Earth using the above (Orbit \& Attitude) disturbance force \& torque functions. 00358 00359 -# Create a Propagator that will propagate the above Orbit \& Attitude objects and using the Environment object. 00360 - Use a linear interpolator for the OrbitHistory. 00361 - Use loose coupling (orbit independent of attitude, but attitude dependent on position). 00362 00363 -# Propagate the orbit and attitude for 2 orbits. 00364 00365 -# Plot the position and attitude using gnuplot. 00366 00367 -# Propagate another 2 orbits. 00368 00369 -# Add the new states to the previously made plots. 00370 00371 Back to: \ref CoupledTutorials 00372 00373 */