-
Notifications
You must be signed in to change notification settings - Fork 1
Home
See the AACT getting started wiki here.
Based on the team's workflow, you'll be doing your work on a personal branch (e.g., dev_taylor). When you have a finished "unit" of work, like fixing an issue or developing & testing a controller, you'll want to integrate your work with the main code on the dev branch. To do this, we use pull requests. I've covered the basics of how to do that here. This process let's us control the flow of updates to the dev branch and helps everyone rebase their local dev branches as necessary.
The flight software will be in C at the end of the day. Because it's autogenerated, we don't have direct control over what individual lines will look like. Instead, we make good Simulink libraries that will autocode into good code. We control things on the Simulink side.
We create Simulink libraries for each block of code. This helps manage editing; when you change something in a library, it will update everywhere that that library gets used. To create a new library, open a Blank Library by using the Simulink front page (by typing simulink at the Matlab command prompt) or by going to File->New->Library... in an open Simulink window. You should see a little lock icon in the lower left corner of the window that opens up. Now:
- Add a blank
Subsystemblock to the empty library file. - Turn off the content preview.
- Save the file using the naming conventions below.
- Name the subsystem according to the naming conventions below.
- Add the guts of the library inside the subsystem. Do not put anything outside of the subsystem.
- Right-click on the subsystem, and select
Block Parameters (Subsystem). Check the box that saysTreat as Atomic Unit. - In the
Code Generationtab, select the appropriate option forFunction Packaging. Which one is appropriate may be different for each library. Ask if you don't know.
To add a Simulink library to a model file, just drag and drop. With both model and library files open, drag the library subsystem into the model file.
Whenever you make a library, you may also need to make an init file. The purpose of the init file is to fill out any constant variables or initial conditions used in the library. We use Matlab data structures (structs) to do this. There are two structs used by the simulation: fswParams and simParams. These two variables contain all of the relevant variables for running the simulation. The distinction is that anything that will be used on the satellite goes into fswParams. Anything that is just there for simulation purposes goes into simParams. Do not bloat fswParams unnecessarily, keeping it as small as possible is important to minimize the memory footprint of the flight software.
To create an init file:
- Create a Matlab function with the same name as the corresponding Simulink library. Save the function file in the same directory as the corresponding Simulink library.
- Give the functions two inputs and two outputs:
[fswParams,simParams] = libraryName_init(fswParams,simParams) - At the top of the function, create a structure:
myStruct = struct; - Populate the struct with variables as needed:
myStruct.myVar = 5;. Whenever you need to reference data from another library or part of the simulation, use the values stored infswParamsand/orsimParams. This ensures consistency across the sim. - Store the struct info in fswParams or simParams:
simParams.myStruct = myStruct; - Add a call to your function to the
init_params.mscript located in the/Includefolder.
Here's a reasonably good example of an init file:
function [fswParams,simParams] = scParams_init(fswParams,simParams)
%SCPARAMS_INIT
%
% Initialize spacecraft parameters. Last sync with SOC-i's CAD model:
% July 16, 2020
%
% T. P. Reynolds
scParams = struct;
% Dimension of cubesat
scParams.z_len = 0.20; % cm
scParams.x_len = 0.10; % cm
scParams.y_len = 0.10; % cm
scParams.m_2u = 2.565438; % kg
% Body normals in the body frame
scParams.xB_dir = [1,0,0];
scParams.yB_dir = [0,1,0];
scParams.zB_dir = [0,0,1];
% Inertia matrix about the CoM & aligned with the body frame axes. Careful
% to convert the CAD output of g*mm^2 into kg*m^2 by multiplying by 10^-9.
scParams.J = [ 11820643.5013, 431707.2662, -7306.1275;
431707.2662, 11636351.4485, -92921.9316;
-7306.1275, -92921.9316, 6034584.4268 ] * 1e-9;
% Point of pressure for S/C and estimated drag coefficent per face. Assume
% geometric center for now, so use -ve of the CoM's location w.r.t. the
% geometric center
scParams.point_of_pressure = [ 2.1986; 2.4908; -8.0777 ] * 1e-3; % m
scParams.CD = 2.2; % standard for 3U cubesat
% Area of the faces of the S/C
scParams.Ax = scParams.x_len * scParams.z_len;
scParams.Ay = scParams.y_len * scParams.z_len;
scParams.Az = scParams.x_len * scParams.y_len;
% Residual dipole moment
scParams.res_dipole_Am2 = [ 0.0; 0.0; 0.0 ];
% Offset about +Z axis to maximize solar incidence in solar panel arrays
scParams.ss_offset_rad = fswParams.constants.convert.DEG2RAD * 40;
% Initialize battery model
% battery_init;
% add to main structs
simParams.scParams = scParams;
fswParams.scParams = scParams;
end
This init file should then be run by include/init_params.m and should be properly commented (tell us what you are initializing!)
This should serve as a reference for whenever we are writing code/onboarding new people. Obviously there will be exceptions to any rule but in general we should really try to follow this.
Variables should be created in their respective init file (for example: all physical spacecraft parameters go in scParams_init.m) and they should follow the following naming convention:
descriptiveName_referenceFrame_units
so in total the parameters will appear in the Matlab workspace as:
simParams.initFileName.descriptiveName_referenceFrame_units
where there can be more subdivisions between initFileName and descriptiveName as needed.
For Simulink library files, use:
libraryName_lib.slx
and the subsystem block immediately inside the library should have the title:
libraryName_lib
Underscores between words can be used if they help.
For init files, name the Matlab function:
libraryName_init.m
For unit tests, name your Simulink files using:
libraryName_test.slx
and any corresponding Matlab scripts used to initialize, run, or analyze the test using:
libraryName_test_init.m
Unit tests are a critical part of developing software, especially in a collaborative environment. Think of a unit test as a simple demonstration that your code does what it is meant to do. You should develop a habit of unit testing everything, even outside of AACT work. Seriously. You should create a unit test once your library is finished and before it gets integrated with the main flight software.
The basic steps are:
- Create a new model file, open a Blank Model by using the Simulink front page (by typing
simulinkat the Matlab command prompt) or by going toFile->New->Blank Modelin an open Simulink window. - Pull in the library that you want to unit test.
- Add inputs and save or display the outputs of the library. More on this in a second.
- Save the file in the appropriate sub-folder of the
/Test/folder. Try to match the location of the library file under/Lib/. For example, if the library under test is located at/Lib/sub/subsub/libraryName_lib.slx, then your test file should be located atTest/sub/subsub/libraryName_test.slx.
On step 3: every unit test will be different, so it's hard to offer more general guidance here. This is where your engineering skills come in: what is the simplest way to verify that the library is doing the right thing? How can you make sure that you test each edge case of the library's functionality? For example, if you've built in a safety guard to catch a divide by zero condition, you should be creating those conditions in a test and showing that your library responds properly (ie, does not return NaNs).
Unit tests will almost always be checked by someone else at a later date. Resist the temptation to just slap something together. We'll all do it at some point, but the less we do the easier it will be to collaborate and understand each other's work.