Favour Adekola's Notebook - cps-vip/cps-cosimulation-env GitHub Wiki

Spring 2026

Week 1

  • Joined the Discord for the class
  • Learned about what Cyber Physical Systems (CPS) are and more specifically the general overview of American power grids and the goals of the CPS VIP
  • Explored the different teams and responsibilities of the CPS VIP and filled out the team form

Week 2

  • Learned about the breakdown for the power system cosimulation and the purpose of PyPower, ROS, Helics, and GridLab-D in regards in simulating everything.
  • Joined the device security sub-team
  • Learned about device security tasks and expectations around Physical Unclonable Functions (PUFs), Side Channel Attacks, Disk Encryption, and Fault Injection.

Week 3

  • Met on Sunday, January 26th to work on slides
    • Started the basic outline of the goal and tasks for PUF slides
    • Proposed sticking to the Red Team and Blue Team split would be helpful for the Kickoff Presentation
  • Helped present PUF slides at the Kickoff Presentation on Thursday, January 29th
    • We were given feedback to make sure we focused on what we would actually be able to do in the class and considering realistic profiles for malicious actors.
  • PUF Specific feedback dealt with a change in our immediate tasks:
    1. Find SRAM Chip with a dev board that can communicate with raspberry pi (This will ideally go onto the physical robot so we have a physical medium we can use to design our PUF algorithms
    2. Work on how to communicate with the SRAM Chip (This may take looking into various communication protocols like I2C)
    3. Do research on how to build a PUF from initialized memory of SRAM.

Week 4

  • Reached out to ROS/HELICS team about their SRAM Chip for the Robot, they currently run off of an ESP32

    • They did not have a set chip selected, so I decided to look at possible candidates myself
    • Base Requirement: The chip has to lack an internal power-on reset (POR) circuitry which would zero out memory and make a unique memory signature unobtainable.
  • I Read the ROS/HELICS final presentation from 2025 to get the general hardware requirements Started looking into possible SRAM Chips for the Robot:

    • Microchip 23LCV1024 - 2.5 - 5V and generally slower than the next option; SPI interface (Raspberry Pi can accomplish this)
    • ESP-PSRAM64H - Generally higher performance and 3.3V; SPI Interface (Raspberry Pi can accomplish this)
  • We got information about a couple of papers to look through about using SRAM PUFs for key generation:

  • We are also looking to ultimately use the SRAM on a STM32 micro controller which will mean learning embedded Rust and the STM32 framework

Week 5

  • Still looking into SRAM chips for ROS/HELICS team since they decided they would want an external chip to integrate it into the logic PCB. They were fine with any interface because they have a variety of free pins to use but would want 3.3v logic if possible. This makes the ESP-PSRAM64H from before a higher contender for a viable chip.

  • I used Digikey to compare across a handful of SRAM chips. We don't want an EERAM or Psuedo SRAM (PSRAM). PSRAM is just DRAM that behaves like SRAM to our computer which may lead to inconsistencies trying to port our findings across different SRAM chips. EERAM is non-volatile and behaves like a mixture between SRAM and Erasable Programmable ROM (EEPROM). Ultimately, I decided on: https://www.digikey.com/en/products/detail/microchip-technology/23LC1024-I-ST/3543085. This chip is a better choice than the ESP-PSRAM64 from before which, mistakenly, is a piece of PSRAM.

Week 6

  • We decided on tasks for the next couple of weeks as well as received two STM32s

    • Learn Rust and Embedded Rust
    • Check the STM Linkers and ASM Bootloaders and make sure they do not zero out memory
    • Use Rust to read half of the memory from the STM32 SRAM without writing into it
    • Test each board we were given for randomness
  • I already knew a good bit of Rust, so I will be looking into Embedded Rust and learning that.

    • I will be learning following with this resource: https://docs.rust-embedded.org/book/
    • I recommend anyone learning Rust should use the standard Rust Book or The University of Brown Rust Book as well as following with practice examples using rustlings

Week 7

  • We worked on midterm presentation; I helped present and write slides for the PUF sub team.

  • I started going through the Embedded Rust and Embassy book and setting up my embedded rust environment

    • The important steps were to:
      1. Install Rustup (Install Rust and Cargo)
      2. Install ST-Link Drivers (This is what your computer uses to recognize the STM32 connection)
      3. Install probe-rs via cargo (This is what lets your computer view the logs/memory of the STM32)
    • THIS LIST MAY NOT BE COMPREHENSIVE (I also ran this on Windows) LOOK AT THE RUST BOOK, EMBEDDED RUST BOOK, AND EMBASSY BOOK FOR BETTER DETAILS ON WHAT TO INSTALL

Week 8

  • I ran an example project on the Embassy book to test board compilation, and everything functioned properly. I was able to blink the LED on the board.

    • Cargo run uses .cargo/config.toml to specify probe-rs should run binary for the hardware.
  • I made a demo project that read a word of memory from the STM32's SRAM4.

    • The template was taken from the Embassy STM32 example project (For our specific board).
    • A word for the STM32 is 16 bits, so every memory address stores 16 bits.
    • memory.x has the starting location and size of all memory addresses on the STM32
  • Hayden gave the task of:

    • Try and Write the data into a file.
      • Maybe attempt to Pipe terminal into a file or Check if there's a way to log directly into a file
    • Print out all memory, do this multiple times
    • Compare bits across runs.
    • Count # of times it flips between 0 and 1 for a bit. (Keep track of which bit this is too)
    • Compare across different boards.

Week 9

  • I made a more in-depth project to instead start to dump the bottom half of memory into logs, doing 20 trials for each STM32

    • During development I ran into error where the probe was logging data only at around the 130th memory address instead of starting at the first address. I fixed this by adding a bit of delay (500 ms) to the start of the program so that the debugger would not interfere with any of the activity of the logging. I found out that Real-Time Transfer (RTT) to transfer data from the STM32 to the host computer runs into these issues with programs, so being able to wait until the board is prepared to send data is a typical fix.
    • Trying to perform logging without the debugger would also cause errors (ASCII character nonsense being printed to the files), so I stuck with running everything with the logs.
  • I made a GitHub repository for the PUF sub team and posted my code and the data there, so that other could also work on it.

Week 10

  • Started on research for Error Correction Codes(ECCs).
    • Mainly getting all of my information from this paper: Comparing ECCs
      • The ECC is the core of the fuzzy extractor. Its job is to fix the bits that changed between the first and second measurements. The paper compares several types of ECCs to see which ones work best in different scenarios.
      • Once you get past all the math and proofs the paper argues that there is no perfect code. The best ECC depends on three trade-offs between 1) Reliability vs. Security, 2) Complexity, and 3) Error Distribution.
      • In other words the ECC we chose needs to be able to correct a certain number of bit flips without removing jeopardizing the benefit of having a random PUF, it needs to be capable of running on the STM32 in a timely fashion, and it should account for the pattern of errors we see in our SRAM which are randomly distributed across the memory unit.

Week 11

  • Spring Break, Not Much work done outside of research

Week 12

  • Started on a template for a fuzzy extractor via Rust. A lot of the implementation can't really be done until a proper ECC scheme is decided.
image
  • How I understand the Fuzzy Extractor currently:

    • Generate (Also called Enrollment) - Where we use an Error Correction Code to create helper data to help make a noisy signal into a constant, valid signal.
      • Input: Raw PUF
      • Process: Use ECC to build a codeword, the helper data is the XOR of the PUF and the codeword.
      • Output: Helper data
    • Reproduce - Build our constant Key with the helper data
      • Input: raw PUF and the Helper Data
      • Process: XOR with helper data, run a ECC decoding algorithm to obtain the key
      • Output: Constant Key
  • Hayden gave tips on how to decide what ECC should be used. We need a measure of our average bit instability and a measure of Intra-chip Hamming Distance. (I still have no clue if these terms refer to the same thing or not)

Week 13

  • Recorded 20 more trials for both the 1724 and 5223 STM32s
  • Edited the PUF analysis python scripts (analyze_bit_stability.py) to help us also get a reading of average bit instability for the board and the intra-chip hamming distance as a percentage.
image image
  • Hayden Confirmed that BCH codes would be a strong ECC for our use case and so I will be moving forward on trying to find the parameters for this.
    • BCH is parametrizable, so you can adjust it based on your needs, with the caveat that it looks like the size and computational complexity increases the more bits you need to correct.

Week 14

  • Created a script (find_bch_parameters.py) to find the parameters for BCH that fits our target for our probability to fail. It uses a cumulative binomial distribution to determine the maximum probability failure and how many bits that will need to be corrected in order to achieve the failure rate desired by a given parameter input. This is important to find the parameter t which is how many bits we will need to correct to get our desired outcome. We originally ran this code using the average bit instability as the Bit Error Rate (BER), but switched to the intra-chip hamming distance since we thought that this was a value more representative of the BER.
    • ex: BCH(511, 65) would fail to initialize the BCH object, but BCH(511, 23) works.
    • note: the bchlib takes parameters m and t. m describes the number of bits n and is related as n = 2^m - 1
image
  • Here's the input for the parameter finding script:
    • block_sizes represent the total block of memory (in bits) we will use to build our helper data to correct our codeword.
    • target_bits represents the number of bits we can expect to retrieve at the specified error rate
    • my_ber represents the bit error rate for the SRAM chip being tested
    • max_p_fail represents the maximum failure you wish to see from the resulting BCH ECC.

Here are the final stats for our two Boards:

image image
  • k represents the number of bits we can expect to hold our secret with. A negative k occurs when our results are so noisy that we will not have any bits left over for our secret.

  • Created a script (test_bch_correction.py) to check how our parameters of BCH perform on our tested recorded trials of the SRAM. It uses the python bchlib to access an encoder to first generate helper data using an arbitrary secret key (In our case it is "This is a secret", a 16-byte string) and the reference PUF/Bitstring. This helper data will then be used for the reproduction phase to take a single noisy trial, XOR with helper data, BCH-correct back to the enrolled secret. A limitation of the BCH library is that certain parameters will not accurately create a proper BCH object. For instance, attempting to use t > 64 will cause an error as the library caps t to 64 for better performance. Since we plan on using this library on embedded devices, it is important that we stay within a t range that can run at acceptable speeds while accounting for the error. At the same time it is not always possible to use a higher value of t since we need a high enough value of n (total block size) in order to provide enough helper data.

    • We originally used single trial enrollment to build our helper data, but as discovered by https://ieeexplore.ieee.org/document/8824887 it results in a larger Bit Error Rate since one trial can vary immensely from every other trial. The second approach we decided on was also used in the paper, majority vote. Majority Vote essentially says that each bit should take the value that occurs most often among all 40 trials. This is essentially the average, most common basis for our PUF with minimized error among all trials. It has a lower BER than the one trial comparison.

Single Trial Reference Bit String

image

Majority Vote Reference Bit String

image

You'll notice that the error seems to cap out at around 30. If we bring t to be greater than or equal to 30 then we will pass all trials as test cases.

  • We noticed that the failure rate of our initial parameter finding script did not line up with the results of the test script. I discovered that the issue was that our understanding of the BER was wrong. Intra-chip Hamming distance is not the Bit Error Rate, but rather a function of the bit error rate. I am still confused on the specifics, but the intra-chip hamming distance is more like a measure of variance to describe the chip as a whole. The average bit instability is a measure of how likely a single bit may be in its minority state. The Bit Error Rate is the error we notice when comparing a reference bit string to other bit strings.

Week 15

  • I helped make slides for the PUF team for the final presentation and presented some of the slides dealing with error correction codes and BCH.

    • We were asked a question on if we had any data on the weakness of the PUF. This can be achieved by looking through our bit match analysis for the per board trials that we performed and just getting a general statistic from the board. We ideally want the boards to have around 50% difference in bits.
    • Additionally, Since the Fuzzy Extractor flow in test_bch_correction.py is going to be a common scheme across PUF material, future presentations would benefit from having a diagram or flowchart explaining the algorithm which would be better than trying to walk through the code. I recommend the diagram having some sort of toy example that you manually rearrange the bits for. Maybe a Fuzzy Extractor where the secret is a singular character which could be achieved with BCH parameter where m = 7 (127 bit block).
  • Moving forward, the PUF team should focus on implementing the fuzzy extractor script onto the STM32s, so that enrollment and reproduction can occur in real time. The bchlib used in the python library should be the same library used for Rust implementation, and I believe it is optimized for use on embedded devices by default (https://lib.rs/crates/bchlib).

  • Additionally, currently, the Bit Error Rate is very large for a block size of 511. If we attempted to use BCH using the parameters n=511 and t=23 we would see a 40% failure rate from the 1723 board and a 28% failure rate from the 5223 board. To combat this, we should increase the block size used for the fuzzy extractor as well as increase the number of bits corrected. We can only increase t proportional to the size of n to a limit of 64. There may be a way to increase t past 64, but that may have adverse effects on the efficiency of the BCH implementation provided by the library

  • Another means to improve the Bit Error Rate would be to "manually" pick out the more stable bits from the PUF when we look to achieve a random PUF for reproduction. Generation/Enrollment will also need to be tweaked so that our majority vote is only focused on bits that are stable. The PAPER uses an approach to make the bits behave in a Ternary fashion. This means that for unstable bits they mark it as an X to have the computer avoid using it for their PUF implementation. Using the information from these two bullet points would help build a more reliable PUF that could actually be used for consistent key generation.

  • As another project, the PUF team can look into building their understanding of SRAM PUFs by testing them in a variety of conditions and environments. This could be cooling the temperature in a freezer/fridge, using a blow dryer to increase the temperature, or playing around with voltages going through the STM32 to try and get varying bit readings. Ideally, we would want our PUF to be stable across environmental conditions. This is more important for the Robot since it could need to communicate with the Grid from a variety of locations. We do not want the Robot to lose its ability to authenticate using its PUF.

Overall, it was a great semester, and I enjoyed working on the PUF team. Good luck all who read this in the future. Sorry for the vagueness in the beginning of the semester.

Fall 2026

Week 1

Entry 1

  • Present for the Class Meeting where Hayden discussed the syllabus and overall VIP project
  • Expressed interest in the ROS/HELICS team for this semester
  • Started thinking about what sort of work I would want to do this semester and decided that I wanted to work mainly on software dealing with robot autonomy, if possible, but understand there will be a lot of work done on just general integration software across the physical robot, the simulation, sensors, etc.
  • Looked for some of the past members of the ROS/HELICS team to gather resources for a notebook deep dive later in the week.
    • Sabina, Elliot, Esha, and Calvin

Entry 2

  • Began reading through Sabina's Notebook to see where the team left off and what work was left to accomplish. I only took notes on the software side since that's where I expect to do most of my work.
    • Sabina noted that she wanted to complete rotary encoder integration and testing with the STM32
    • Need enable bidirectional odometry tracking and to tune the Motor PID Loops
    • Work to be done on the Sensor Fusion side to get positional estimates from Encoder and IMU (Process and Measurement noise covariance definitions)
    • Need to transition from Simulated LiDAR to the physical LiDAR devices
    • The actual Simulation will most likely need a programmatic way to place waypoints at fault locations instead of having a manual/GUI methodology of doing so.
  • The Key Repositories I will have to look through later to confirm the necessity of the above work would be:

Week 2

Entry 1

  • Looked at previous Final Presentation and Kickoff Presentation and began noting some changes to make before the Kickoff Presentation this year.
    • Mission 1 focused on getting simulations live and running and work on Mission 2 of getting the robot running physically had begun.
    • Focus for this semester should be to demonstrate an autonomous, physical robot that navigates a real-world environment using onboard sensors and algorithms, directly responding to fault injection events triggered within the HELICS/GridLAB-D co-simulation stack.
    • A successful Mission 2 contains 4 main features:
      • Physical Locomotion & Low-Level Control: The differential-drive base drives stably under closed-loop PID control on the STM32, backed by clean quadrature encoder feedback (no erratic count spikes) and hardware PWM.
      • Bidirectional Serial Bridge: The Raspberry Pi ROS 2 node reliably receives encoder telemetry from the STM32 and publishes velocity target converted to whatever the STM32 can read.
      • Real-World Sensing & SLAM: The physical 360° LIDAR and IMU maps an indoor environment via SLAM and tracks robot pose
      • End-to-End Co-Simulation Response: When a fault is triggered in the GridLAB-D reliability module inside Docker, the Control Center federate transmits the target coordinates to the physical Raspberry Pi, commanding the real robot to autonomously drive to that inspection waypoint

Entry 2

  • I started making my way through the ROS/HELICS repositories. Spent time trying to get everything running locally and this is the process I went through:
    1. Cloned the Key repos I identified in Week 2
    2. Followed README in NAV2 Repo for initialization help. It wasn't very clear at first, but I had to add my own Dockerfile to the repo to add in any of the code they said we should add in. Continued to create the Docker Image.
  • I got stuck at this point since I was encountering not very descriptive errors working with getting the Cosim up and running with NAV2 as well, so I called it for the day and worked on getting a indepth setup plan using Gemini and seeing if it can find anything wrong with my current setup to match up with the instructions provided by the repositories.

Week 3

Entry 1

Had a 15-minute team meeting discussing what changes we should make for the Kickoff presentation. I explained we should focus the semester on Mission 2 work and that our presentation will start with showcasing what Mission 1 would leave off on and then move into what we need to do to accomplish Mission 2 work.

Entry 2

Worked on the Kickoff presentation. Made the general ordering of the slides as well as the GNC slides and Fault Integration slides. I'm from a aerospace background when it comes to robotics, so I refer to the autonomy algorithms like path planning and navigation as Guidance Navigation & Control (GNC).

Week 4

Entry 1

Finished setting up the Simulation and got it to run together: image

I noticed that the project only works if you use Elliot's version of the Cosim-fault-integration repository on a specific branch and he made a PR into the cps-vip/cosim-fault-integration repository. I reviewed the PR and verified that there were no major diffs between his version. The changes he made focused on moving from nix based container setup to nix container setup. I cannot merge the PR myself, so I will bring it up with Hayden so that he can merge it for us.

Entry 2

Began working on a script to help run the entire simulation in one script instead of having to create 4 terminals manually and remembering the commands to run each of them each time. There was also an issue with how I was running the 4th terminal where a second instance of Gazebo and RViz would start up and cause conflicts with the existing versions of Rviz, so my script will also hopefully change/circumvent those issues. Scope of changes

  • Remove the RViz and Gazebo initializations from the GridLabD startup procedures
  • String the 4 scripts (launch_sim.launch.py, navigation_launch.py, waypoint_publisher.py, cc_run_example.sh) into one script to run to startup anything related to the simulation.

Week 5

Entry 1

During the meeting we talked about switching from the STM32 board to a zynq700 board instead for onboard robot computation tasks. We found a Hardware Abstraction Layer (HAL) for embedded rust that was already being worked on and open sourced: https://github.com/ustgt-irs/zynq7000-rs/tree/main

I made a new branch for the robot_pid_controller repo called zynq700halswap. Most of the changes were pretty one to one from the STM32-embassy library we were already using, the biggest change was moving from a Cortex-M processor to a Cortex-A9 processor. The code was verified using cargo check to make sure it was capable of compiling, but next step is to actually bring it onto hardware and ensure that work remains viable. Only thing that needs to be added is to replace the AXI placeholder addresses with actual addresses as we define them on the board later via Vivado. Created a TODO comment as a reminder when the time comes. image

Tried to push the code to its own branch, but I don't believe I have access to the repository:

image

Entry 2

I spent some time looking through the codebase for the cosim-fault-injection to understand how to implement physical mapping for fault injections. Need to deliberate on exact approaches for what we want to accomplish and whether or not the injection should be something controlled by the Control Center or the robot or a mixture of both in the end. For now, we could create a rough estimate of the sizing of the room (which I will verify this Thursday), choose where simulated components exist in real world. These coordinates can be updated for the SUBSTATION_MAP in waypoint_publisher.py

image

or in the Trigger condition of CC_simulator.py.

image

Either coordinate is consumed by navigation algorithms so it would be up to tunning our PID to have the proper rate conversion we require from digital logic to physical motion that will solidify our coordinate mapping. the slam_toolbox used by the robot assumes that wherever the robot starts is the origin (0,0), so if our mapping is static, we would have to start the robot at the same location each time or change the SLAM usage and give the robot a map already provided and have it focus on localization within the map.

Week 6

Entry 1

Went back to finish up the simplified script to run the simulation in the loop with the NAV2, Gridlab-D, and Gazebo. It has helped to circumvent the issues that occured with the set up tutorial given for the 4-terminal approach from before. Here is the script running in the terminal:

image

The actual results are identical to what was captured in Week 4. All code is saved on a branch in the cosim-integration-fault repository called simplified_example_run_script. I also took the moment to add my changes to the robot pid repository to it's own branch on the Github as well since I was able to request push permissions.

Entry 2

Looked into the error I got previously in Week 5 when attempting to run the simulation with the given defaults from last semester (essentially told the robot to move to a fault located at [5,-3]). Ran into a 204 Error from Nav2 and SLAM which corresponded to a GLOBAL_OUTSIDE_MAP error.

image

Looked into the error and found out that when the simulation starts, slam_toolbox initializes an empty map and only knows about the space its LiDAR beams can currently see (roughly a 2.5 to 3.5 meter radius around the origin (0,0)). This is defined by a NAV2 config called track_unknown_space.

image

When [5.0, -3.0] was sent (which was around 5.8 meters away), the point was outside the current boundaries of the SLAM map grid. Nav2's global planner errored to avoid calculating a path through unmapped area. This could be circumvented by mapping the class area beforehand either through a preloaded map or by giving the robot a roaming/exploration state that will just check the area around until a fault location is given. Alternatively, we could bound the waypoints of the robot to redirect any out of map waypoints to be mapped to the closest explored area by the robot. This is less intuitive and better handled by a more logical guidance algorithm, but with respect to the end goal of the robot, I believe it would make more sense to introduce a wandering stage for the robot to explore its surroundings, so that if it got a fault occurrence it would understand where that fault is exactly and it wouldn't be sent somewhere else in attempts to get there. Additionally, we could do things like loading a map onto the robot beforehand and having SLAM function as a means to edit that map in real time in case the environment changes or the substation gets additions over time. For immediate testing, a roaming approach seems most logical.

Week 7

Entry 1

Looked into the mapping issue for the robot from last week. Figured out a method of performing pre-mapping, so instead of remapping the empty room every time the simulation boots, we can just preload a map. This requires driving the robot around whether manually or autonomously beforehand and then saving the map using ros2 run nav2_map_server map_saver_cli -f ~/software/ros2_ws/src/NAV2/src/vipnav/maps/substation_map and then load the map into Nav2 on startup which is already performed via the substation_map.yaml logic. Decided not to go through with code for the pre-exploration since it is likely to be scrapped and not used for future iterations of the project and overall, not useful. The better option is to do a manual drive of the robot to create a map when we get it physically built out and then we can save that map for future iterations.

The map meta data is saved as mapSave.yaml in NAV2:

image

The actual map is saved under mapSave.pgm in NAV2 and can be updated if we save the map after running the robot.

Entry 2

Couldn't put as much effort technically this week since I needed to fill out the rest of the new VIP capstone proposal from: https://sites.gatech.edu/csvipevaluation/cs-vip-capstone-proposal/#submit

Worked on the Introduction section and began working on the Research, Roadmap, and Approach which has allowed me to look back at other notebooks for the ROS/HELICS team to get a stronger understanding of the project.

⚠️ **GitHub.com Fallback** ⚠️