-
Notifications
You must be signed in to change notification settings - Fork 5
RockBLOCK Reports
The Rockblock Report Monitor is responsible for switching between the three types of Rockblock downlink report types: normal_report
, camera_report
, and imu_report
. The definition and implementation for the Rockblock Report Monitor lives in RockblockReportMonitor.cpp
and RockblockReportMonitor.hpp
. The execute()
method is called every main control loop cycle.
void schedule_report()
- Switches the current report type based on current state of
sfr::imu::imu_dlink_report_ready
, the current time,sfr::rockblock::last_downlink
, andsfr::camera::report_ready == true
. - The IMU report has the highest precedence, followed by the normal report, and the camera report.
void execute()
- Executes the scheduling report logic and updates the report type.
- Low power modes only allow normal reports
- All other modes alternate between the 3 kinds of reports (no priority)
- Camera reports and IMU reports should only be downlinked if they are "ready". If one report is "ready" but another is not, the one that is "ready" should be downlinked
- For example, if neither the imu report nor the camera reports are "ready" the normal report should be downlinked without waiting for them to be "ready"
The Normal report downlinks a variety of satellite-specific general data. The specific values and data points from the sensors and Rockblok can be found in the table below. The report may be as long as 70 bytes but can be as short as 33 bytes.
Format for downlinked data.
Index | Data | Min (if applicable) | Max (if applicable) | Units (if applicable) |
---|---|---|---|---|
0 | 99 (normal report flag) | N/A | N/A | |
1 | photoresistor covered | |||
2 | button pressed | |||
3 | mission mode | |||
4 | burnwire burn time | 0 | 5000 | milliseconds |
5 | burnwire arm time | 0 | 864000000 | milliseconds |
6 | burn wire mode | |||
7 | burn wire attempts | 10 | ||
8 | downlink period | 60000 | 172800000 | milliseconds |
9 | waiting message | |||
10 | waiting command | |||
11 | mag_x | -150 | 150 | microTesla |
12 | mag_y | -150 | 150 | microTesla |
13 | mag_z | -150 | 150 | microTesla |
14 | gyro_x | -5 | 5 | rad/s |
15 | gryo_y | -5 | 5 | rad/s |
16 | gyro_z | -5 | 5 | rad/s |
17 | photoresistor | 0 | 1023 | |
18 | temperature | -50 | 200 | Celsius |
19 | solar current | mA | ||
20 | in sun | |||
21 | voltage | 3 | 5 | Volts |
22 | fault1 | |||
23 | fault2 | |||
24 | fault3 | |||
25 | camera powered | |||
26 | EEPROM boot counter | |||
27 | packed sensor faults | |||
28 | packed sensor faults 2 | |||
[29...48] | mission mode history | |||
49 | delimiter ('0xAA') | |||
[50...67] | opcodes of received commands | |||
report.size() - 2 | 254 (end flag 1) | |||
report.size() - 1 | 255 (end flag 2) |
Indices 27-28 are assigned encoded sensor validity data in a bitwise manner in the following order:
27 — mag_x_average, mag_y_average, mag_z_average, gyro_x_average, gyro_y_average, gyro_z_average, temp_c_average, solar_current_average
28 - 000000, voltage_average, photoresistor_average
The contents of indices 30-70 will vary based on the length of the mission mode history (max 20 bytes/mission mode switches) and received opcode sections(max 18 bytes/9 opcodes). The numbering in the table above illustrates the maximum length state of 70 bytes.
In MainControlLoop.cpp
, normal_report_monitor.execute_on_time()
will be called every cycle. This will generate the report to be downlinked by filling in the sfr::rockblock::normal_report
. Specifically, the function will first obtain the data necessary for generating the normal report. It will then continuously push the relevant information onto the sfr::rockblock::normal_report
queue. Sensor data that does not fit in a 1 btye integer will be packed using the mapping bounds above. It will then append the list of opcodes of received uplink commands, which is stored in NormalReportMonitor::commands_received
, to the normal report. Finally, it will append the two end-of-downlink flags to the report. When the logic in RockBlockReport Monitor determines that it is time for a normal report to be downlinked, the generated report will be downlinked to the ground.
Opcodes of received commands will be added to the normal report to help team members understand what the satellite has received. It will contain at most 15 commands since the last downlink, with each command's opcode taking two bytes. The positions of these opcodes could be found in the table above.
In general, IMU Downlink is a piece of code that manages a buffer consisting of IMU gyro data. The buffer, which is called imu_dlink
, provides gyro data content for the IMU Report. The buffer is initialized inside the imu
namespace of sfr
. The buffer does not have a constant length. Instead, the gyro data will be continuously pushed into the buffer within a predefined time period. The buffer is a deque with type uint8_t
. Whenever we need data from the buffer, we will pop the data from its back. The deque is used as a FIFO (First In First Out) buffer.
A whole IMU report consists of multiple IMU fragments(number varies). We need multiple downlinks to downlink each IMU report fragment (70 Bytes each with every byte represented in Hex). The IMU report fragments will be downlinked after we successfully populate the gyro data(gyro-x, gyro-y, gyro-z) to the IMU Downlink buffer. We downlink one fragment every command cycle and only stop downlinking when the buffer(imu_dlink
buffer) that we popped data from becomes empty. We didn’t expect the number of fragments to exceed the maximum capacity we set for it given we won’t downlink too much data, but we’ve taken care of this situation. There will be 18 fragments that add up to a total of 1,188 bytes of gyro data which is equivalent to 39.6 seconds. It is timed to 20 seconds before the door is opened, 9.6 seconds while the door is opening, and 10 seconds after the door is opened.
Sent: 70 Bytes (140 digits)
Report ID: 18 (in Hex, 1 Byte)
Fragment Number: starting from 00 and increasing by 1 (in Hex, 1 Byte)
End Flag: 0xFE92 (in Hex, 2 Bytes)
Cycle the following content:
- Gyro-x value (in Hex, 1 Byte)
- Gyro-y value (in Hex, 1 Byte)
- Gyro-z value (in Hex, 1 Byte)
22 complete cycles total of 66 bytes
Example:
Given that we have 70 bytes, the report ID is 0x18, the fragment id is 0x00, the end flag is 0xFE92, the gyro-x value, gyro-y, and gyro-z values are all 0x7F, this report fragment should look like:18007F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7F7FFE92
-
In MainControlLoop.cpp
, theimudownlink_report_monitor
object will be called on theexecute_on_time()
function to start executing the IMU downlink report monitor; -
IMUDownlinkReportMonitor::execute()
inIMUDownlinkReportMonitor.cpp
will be called; - The IMU report fragment will be downlinked if
sfr::rockblock::imu_report
is empty,sfr::imu::report_written
is true, andfragment_number
is less thansfr::imu::max_fragments
;-
sfr::rockblock::imu_report
is cleared every time a fragment is transmitted. When this happens, we are able to load in the next fragment for transmission; - To make
sfr::imu::report_written
betrue
, we need to have IMU data be pushed to theimu_dlink
buffer for 60 seconds after successful deployment, which is indicated inside theIMUDownlink::execute()
function;
-
- Inside the
IMUDownlinkReportMonitor::execute()
, functioncreate_imu_downlink_report(int fragment_number)
will be called to create one IMU downlink report fragment from theimu_dlink
buffer- Inside the
create_imu_downlink_report(int fragment_number)
function, we first push the IMU report ID to thesfr::rockblock::imu_report
. The number will be pushed in decimal because it will be later convert to Hex in ground station side; - Then we will push the fragment number to the
sfr::rockblock::imu_report
; - Then we will push the gyro-x, gyro-y, gyro-z values in order to the
sfr::rockblock::imu_report
; - The gyro values will be popped out from the
imu_dlink
buffer as well; - We will have 22 complete cycles;
- Inside the
- After successfully creating one report fragment,
sfr::imu::report_ready
will become true to indicate successful report population; - Outside the function
create_imu_downlink_report(int fragment_number)
,sfr::imu::fragment_number
will be increased for the next fragment downlink; - We will continue downlinking the IMU report fragment until: the
imu_dlink
buffer and theimu_report
buffer are both empty, indicated bysfr::imu::imu_dlink.size() == 0 && sfr::rockblock::imu_report.size() == 0
; OR the current fragment number is greater than the maximum number of fragments we could have, indicated bysfr::imu::fragment_number >= sfr::imu::max_fragments
:- In the first case, if both buffers have size 0, the
imu_dlink
buffer is empty and all fragments have been downlinked. Thensfr::imu::report_ready
will be set to false so that in theRockblockReportMonitor::schedule_report()
function so that the main control logic knows it’s not the time to downlink the IMU report; - In the second case, if
sfr::imu::fragment_number
is greater or reachessfr::imu::max_fragments
, we have reached the maximum capacity we could have for the fragments. Thensfr::imu::report_ready
will be set to false so that in theRockblockReportMonitor::schedule_report()
function so that the main control logic knows it’s not the time to downlink the IMU report. Andsfr::imu::fragment_number
will be reset to 0.
- In the first case, if both buffers have size 0, the
-
Make sure you are ESD-safe
-
Connect your computer to the FlatSat with a cable
-
Turn on the power for teensy
-
Make sure the environment is in the
env:simulator
: -
Upload the code to the teensy on the CubeSat by clicking the “->” symbol at the very bottom of your VSCode:
- If you didn’t ever see a message which asks you to press reset button, but instead saw a message in your terminal like:
Programming -----------------------------------------------------------
Then you have uploaded successfully. - Otherwise, Control + C (either on Windows or on MacOS) to stop uploading and continue unscrew the flight screw to make sure you have turned on the CubeSat
- If you didn’t ever see a message which asks you to press reset button, but instead saw a message in your terminal like:
-
Click on the PlatformIO: Serial Monitor icon to start monitor/testing:
- Make sure you are ESD-safe
- Turn on the CubeSat:
- Unscrew the flight screw near the bottom of the CubeSat (this is on the side of the CubeSat, not on the bottom). Tutorial Video here.
- Continue unscrew until you see the tiny orange flash near the bottom (you need to look through the gap parallel to the top of the bottom)
- Connect CubeSat with your computer using a cable.
- Make sure the environment is in env:teensy35.
- Upload the code to the teensy on the CubeSat by clicking the “->” symbol at the very bottom of your vscode (just like what you did for the test on FlatSat)
- If you didn’t ever see a message which asks you to press reset button, but instead saw a message in your terminal like:
Programming -----------------------------------------------------------
Then you have uploaded successfully. - Otherwise, Control + C (either on Windows or on MacOS) to stop uploading and continue unscrew the flight screw to make sure you have turned on the CubeSat
- If you didn’t ever see a message which asks you to press reset button, but instead saw a message in your terminal like:
- Put the CubeSat on the ESD-safe bag (a transparent backpack) and zip up
- Bring both the computer and the CubeSat to the 6th floor of Rhodes Hall
- This is because we have a better signal on the higher floors.
- With your back to the elevator, you need to turn left until you see a gray door.
- Open the door and enter and you will see a large glass stairwell.
- Put the bag and computer on the gray platform near the glass.
- Make sure the antenna is facing to the sky (you might need to lay down the bag)
- Click on the
PlatformIO: Serial Monitor
icon to start monitor/testing
For both testing, you may only want to print the message that is related to your own testing. What you need to do is to set a flag in the build_flags section of the platformio.ini
file and format your print statements in the right way. In this way, the terminal will only show the prints within your flags, making your code more maintainable.
- Go to the file that you want to add print statements
- Add:
#ifdef FLAG_NAME Serial.println(“whatever you want to print out”); #endif
- Reminder:
- println = print + \n
- You can add as many print statements as you want between the
#ifdef FLAG_NAME
and#endif
- The
FLAG_NAME
is what you want to indicate in the build_flags section of theplatformio.ini
file
- Go to
platformio.ini
- Go to your intended env section
- After the build_flags, add
-D FLAG_NAME
- You can add as many flag names as you want. In this way the terminal will show the print statements under multiple flags.
The below example shows the scenario that I’m under the env:simulator
, and I want to print my statements under both the flags VERBOSE_IMUD
and SIMULATOR
.
![Screen Shot 2022-05-07 at 8 03 12 PM](https://user-images.githubusercontent.com/70693130/167276719-f1b37b86-3ebb-4861-8b7e-07384f4d075e.png)
This screenshot shows how I set flags for my print statements inside the code for flag VERBOSE
.
The camera report downlinks fragments of a JPEG image so that we could reconstruct the image taken by the onboard optical sensor on the ground. Its start flag is 42 (2A in hex). After this flag comes the 1-byte image serial number and the 4-byte fragment number. The fragment number would increment by 1 for each camera report since each report is carrying another fragment of the original image. After this is the main content of the image fragment. This part is usually 64 bytes in length. Typically the number of bytes in the original image is not a multiple of the number of bytes in one image fragment, so the last fragment of an image will be shorter than the others. The camera report for that fragment will be correspondingly shorter. To support this variable-length structure, a deque is used to hold the camera report, similar to the normal report.
Format for downlinked data.
Index | Data |
---|---|
0 | 42 (flag in decimal). |
1 | Image Serial Number |
2-5 | Fragment Number |
6-report.size()-1. | Fragment Content |