<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Nelson Herrera]]></title><description><![CDATA[Sharing my projects with the world! One post at a time!]]></description><link>https://blog.herrnel.com</link><generator>RSS for Node</generator><lastBuildDate>Mon, 20 Apr 2026 10:28:13 GMT</lastBuildDate><atom:link href="https://blog.herrnel.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Albatross Project Logs (2/7/2026 - 3/16/2026)]]></title><description><![CDATA[2/7/2026
Basically following this guide right here: https://docs.px4.io/main/en/dev\_setup/dev\_env\_mac

Looks like I need to use an x86 terminal. Neat.

Also looks like we need to install home brew ]]></description><link>https://blog.herrnel.com/albatross-logs</link><guid isPermaLink="true">https://blog.herrnel.com/albatross-logs</guid><dc:creator><![CDATA[Nelson Herrera]]></dc:creator><pubDate>Tue, 17 Mar 2026 01:49:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6860d960c78e0d55066e26e6/77d61faf-e564-4ec4-abbe-433af8cf5496.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h4>2/7/2026</h4>
<p>Basically following this guide right here: <a href="https://docs.px4.io/main/en/dev%5C_setup/dev%5C_env%5C_mac">https://docs.px4.io/main/en/dev\_setup/dev\_env\_mac</a></p>
<ul>
<li><p>Looks like I need to use an x86 terminal. Neat.</p>
</li>
<li><p>Also looks like we need to install home brew again for x86. Looks like it doesn't replace my existing one <code>/opt/homebrew/bin/brew</code> but rather adds it to <code>/user/local/bin/brew</code>.</p>
</li>
<li><p>hmm... my terminal still thinks I should use the old brew even after adding control flow in the <code>.zshrc</code> to use the right one for the right arch.</p>
</li>
<li><p>Ahh, I needed to update my <code>.zprofile</code> to not override what we just put in <code>.zshrc</code>.</p>
</li>
<li><p>Looks like Python3 has tooling for x86 and Arm. woop woop.</p>
</li>
<li><p>Hmm looks like I might need to manually link the python3 installed by brew cause right now it wants to use the the existing old one. I am going to see if px4 lets me do my thang.</p>
</li>
</ul>
<p>Now I am installing Gazebo using this guide: <a href="https://gazebosim.org/docs/latest/install%5C_osx/">https://gazebosim.org/docs/latest/install\_osx/</a></p>
<ul>
<li><p>ChatGPT says that I should use a docker container for "Stability or whatever". I am already this far so we will keep chugging along until something breaks.</p>
</li>
<li><p>Also looks like there 3 flavors for Gazebo. Gazebo Classic, Gazebo Sim, and Ignite/Fortess? Classic is the clear old reliable and Sim might be too new and flaky. I am downloading sim for posterity however if it turns out to be buggy enough Ill move over to classic.</p>
</li>
<li><p>Looks like we can skip running these steps</p>
</li>
</ul>
<pre><code class="language-plaintext">brew unlink tbb
sed -i.bak '/disable! date:/s/^/  /; /disable! date:/s/./#/3' $(brew --prefix)/Library/Taps/homebrew/homebrew-core/Formula/tbb@2020.rb
brew install tbb@2020
brew link tbb@2020
...

brew install px4-sim-gazebo
</code></pre>
<ul>
<li>Still need the following though:</li>
</ul>
<pre><code class="language-plaintext">brew install --cask temurin
brew install --cask xquartz
</code></pre>
<ul>
<li>Looks like I'll have three running processes:</li>
</ul>
<ol>
<li>PX4 SITL (C++)</li>
</ol>
<ul>
<li><p>runs the autopilot</p>
</li>
<li><p>outputs MAVLink on UDP</p>
</li>
</ul>
<ol>
<li>Gazebo (Classic or gz)</li>
</ol>
<ul>
<li><p>runs physics + sensors</p>
</li>
<li><p>talks to PX4 via a plugin/bridge</p>
</li>
</ul>
<ol>
<li>Your Python code (MAVSDK)</li>
</ol>
<ul>
<li><p>connects to PX4 via MAVLink (UDP)</p>
</li>
<li><p>sends offboard commands</p>
</li>
<li><p>runs ML</p>
</li>
<li><p>More detail on all of this can be found [[here]]</p>
</li>
</ul>
<h4>2/8/2026</h4>
<p>Now that we have the toolchain setup we can actually see if we did it right: <a href="https://docs.px4.io/main/en/dev%5C_setup/building%5C_px4">https://docs.px4.io/main/en/dev\_setup/building\_px4</a></p>
<ul>
<li><p>Okay so first step is to run <code>make px4_sitl gz_x500</code>.</p>
</li>
<li><p>Looks like we can run <code>make list_config_targets</code> to view all of the targets available.</p>
</li>
<li><p>Okay so things aren't working. Time for us to take a step back. I should probably use a python environment so that I avoid conflicts with my other python3 installations.</p>
</li>
<li><p>Okay done, now I reinstalling of the python packages and making sure I don't use <code>--user</code> flag since that for the entire system.</p>
</li>
<li><p>Okay that seemed to fix that issue. Now I am getting some errors related to the <code>em</code> package.</p>
</li>
<li><p>Okay I got really confused with the .env stuff. I ended up neede TWO python environments. One is the Homebrew python environment (system tools) which will install PX4 toolchain stuff like <code>px4-dev</code> <code>opencv</code> <code>gstreamer</code>; toolchain + simulator + CMake deps. The other python environment i made was for the PX4’s Python scripts + code generation dependencies. This is where I will be running <code>make px4_sitl gz_x500</code>.</p>
</li>
<li><p>Looks like cmake is looking for a libOpticalFLow.so file but I have a libOpticalFlowSYtem.dylib cause I am on a mac. I need to create a symlink using <code>ln -sf libOpticalFlow.dylib build/px4_sitl_default/OpticalFlow/install/lib/libOpticalFlow.so</code> and make sure i don't run <code>make distclean</code> or the symlink will get wiped.</p>
</li>
<li><p>Well it looks like we got really close. PX4 started running but then the Gazebo simulator died. Looks like libOpticalFlowSystem.dylib depends on a different plugin <code>@rpath/libOpticalFlow.dyliib</code>. The runtime loader failed to find it. I am going to create another symlink in the place where the loader looked so that I don't have to move it around.</p>
</li>
<li><p>Holy canoli that worked...thank god I wrote all of this down. I really don't want to have to relearn all over again.</p>
</li>
</ul>
<p>I am seeing some warnings.</p>
<pre><code class="language-plaintext">WARN  [health_and_arming_checks] Preflight Fail: ekf2 missing data
WARN  [health_and_arming_checks] Preflight Fail: No connection to the GCS
WARN  [health_and_arming_checks] Preflight Fail: No connection to the GCS
WARN  [health_and_arming_checks] Preflight Fail: No connection to the GCS
WARN  [health_and_arming_checks] Preflight Fail: No connection to the GCS
</code></pre>
<h5>“Preflight Fail: No connection to the GCS”</h5>
<p>This is normal <strong>if you don’t have a Ground Control Station (QGroundControl) connected</strong>.</p>
<p>PX4 is basically saying:</p>
<blockquote>
<p>“I’m not armed / not ready because I don’t see a GCS.”</p>
</blockquote>
<p>It does <em>not</em> mean the sim isn’t running.</p>
<p>we can Ignore it for now if we're controlling with MAVSDK.</p>
<p>Now I see this</p>
<pre><code class="language-plaintext">FO  [mavlink] mode: Onboard, data rate: 4000 B/s on udp port 14280 remote port 14030
INFO  [mavlink] mode: Gimbal, data rate: 400000 B/s on udp port 13030 remote port 13280
INFO  [logger] logger started (mode=all)
INFO  [logger] Start file log (type: full)
INFO  [logger] [logger] ./log/2026-02-09/05_25_45.ulg
INFO  [logger] Opened full log file: ./log/2026-02-09/05_25_45.ulg
INFO  [mavlink] MAVLink only on localhost (set param MAV_{i}_BROADCAST = 1 to enable network)
INFO  [mavlink] MAVLink only on localhost (set param MAV_{i}_BROADCAST = 1 to enable network)
INFO  [px4] Startup script returned successfully
</code></pre>
<p>which means that PX4 started multiple MAVLink “instances”:</p>
<ul>
<li><p><strong>Normal</strong> (high data rate) on one UDP port (you saw 18570 earlier)</p>
</li>
<li><p><strong>Onboard</strong> on <code>udp port 14280</code> (low rate)</p>
</li>
<li><p><strong>Gimbal</strong> on <code>udp port 13030</code></p>
</li>
<li><p>plus the other onboard ports you saw earlier</p>
</li>
</ul>
<p>So PX4 is broadcasting telemetry/accepting commands over UDP.</p>
<ul>
<li>Okay lets recap how we are going to be developing our Autonomous Drone:</li>
</ul>
<h5><strong>Terminal 1 (PX4 + Gazebo)</strong></h5>
<p>From <code>PX4-Autopilot/</code>:</p>
<pre><code class="language-plaintext">make px4_sitl gz_x500
</code></pre>
<p>Leave it running. You should see <code>pxh&gt;</code>.</p>
<h5><strong>Terminal 2 (Your Python autonomy code)</strong></h5>
<p>From your autonomy project folder (NOT PX4):</p>
<pre><code class="language-plaintext">cd ~/Projects/AI-Grand-Prix/your-autonomy-project
source .venv3.14/bin/activate   # or whatever venv you use for MAVSDK
python main.py
</code></pre>
<p>That Python script is where you call <code>await drone.connect(...)</code>.</p>
<p><strong>Important:</strong> You do <em>not</em> type <code>await drone.connect(...)</code> into the PX4 <code>pxh&gt;</code> shell. That shell is only PX4 commands. To learn more about the architecture and how these systems communcate look at [[Development Environment Explained]]</p>
<p>Now we have to create our ML python environment.</p>
<ul>
<li><p>I created another <code>venv</code> for the Albatross project.</p>
</li>
<li><p>I created a <code>connect_test.py</code> to test the connection to PX4 using the <code>MAVSDK</code></p>
</li>
<li><p>Looks like udpin for port 18570 is being used by px4. I think we can still use udpin but its best to go for a different upd port.</p>
</li>
<li><p>we should use 14540 where udpin and udpout should be unused.</p>
</li>
<li><p>We can check which port is currently being used by running <code>lsof -i udp:14540</code></p>
</li>
<li><p>I remember that whole architecture and the “3 modes” plan (full / partial / degraded) with the adapter layer + fault injector.</p>
</li>
</ul>
<h4>2/9/2026</h4>
<ul>
<li><p>Alright so for the next day or so we are in system design mode. We should look into some existing autonomous vehicle repo's and try to glean as much as we can about how they structure and even solve their autonomous problems (without copying of course). This will give me a good Top-down system design that I start off with.</p>
</li>
<li><p>I found this really nice paper on ArXiv thats called <a href="https://arxiv.org/html/2506.11400v1">A Step-by-Step Guide to Creating a Robust Autonomous Drone Testing Pipeline</a></p>
</li>
<li><p>"To manage this complexity, modern autonomous drone systems are typically organized as multi-module architectures, where each functional component (e.g., perception, localization, planning, control) operates semi-independently and interacts through well-defined interfaces (Liang et al., <a href="https://arxiv.org/html/2506.11400v1#bib.bib41">2025</a>). This design paradigm, often built on middleware platforms such as the Robot Operating System (ROS) (Quigley et al., <a href="https://arxiv.org/html/2506.11400v1#bib.bib56">2009</a>), mirrors practices in broader autonomous driving systems (ADS) (Deng et al., <a href="https://arxiv.org/html/2506.11400v1#bib.bib19">2022</a>). Indeed, the majority of ADS practitioners report working on modular systems rather than monolithic end-to-end models, citing scalability, debuggability, and safety as primary motivators (Lou et al., <a href="https://arxiv.org/html/2506.11400v1#bib.bib43">2022</a>)."</p>
</li>
<li><p>"These nodes interact using standard ROS messages (e.g., sensor_msgs, nav_msgs, geometry_ msgs) and services, enabling asynchronous and real-time communication. Developers can also use visualization tools such as RViz (Kam et al., <a href="https://arxiv.org/html/2506.11400v1#bib.bib37">2015</a>) to inspect published topics (e.g., marker poses, planned paths) and use rosbag to record and replay test data."</p>
</li>
</ul>
<p>I really like this Software Architecture they provide</p>
<p><img src="align=%22center%22" alt="[Pasted image 20260211193903.png]" /></p>
<h4>2/11/2026</h4>
<ul>
<li><p>I think to increase my understanding of modern CV, architecture, and planning algorithms I am going to use Litmaps.</p>
</li>
<li><p>Then I need a good way to organize these documents in a way that will make it easy to synthesize the best algorithms for this drone. I think I'll use Zotero to keep track of the things I read and make a mental note of the most interesting parts for each of them. There is a way for me to use tags which will make it easy to group them up and do a real cross comparison. I might use the modules as tags since that's what I am looking to optimize. I'll even throw in an architecture tag in the case a paper proposes a new architecture.</p>
</li>
<li><p>Finding papers and categorizing them should be a good portion of my time since the actual rules surrounding the competition are still up in the air. I still don't know if we will have the opportunity to train our models on simulations they provide or what kind of compute will be used in the Simulations and IRL drones.</p>
</li>
<li><p>As I have been doing research I have realized that making sure my python modules works in realistic simulations is a must. After getting a simple flying module set up with Gazebo and PX4. I believe getting Isaac and AirSim working next week should be my goal.</p>
</li>
</ul>
<h4>2/12/2026</h4>
<ul>
<li><p>Research, Research, Research.</p>
</li>
<li><p>hmm, the closest competition I can find related to this one seems to be surrounding the A2RL which contained teams to only use a single rolling shutter CMOS camera and prohibiting any external aids at any stage.</p>
</li>
<li><p>We should learn about the top competitors from that competition and what they used for their system architecture.</p>
</li>
<li><p>Hmm... so the team was TU Delfts Mavlab. They've really been pushing the envelope reaching top speeds of 28 m/s. Well my goal should be to get to 40 m/s. High hopes but I think that's what it will take to ensure a victory. At least from a speed standpoint.</p>
</li>
<li><p>Hmm so during the AlphaPilot/AIRR competition they used motion capture and in the A2RL they didn't. I feel like they some how use motion capture to train supervise a NN using it as Y and comparing it to Y-hat.</p>
</li>
<li><p>They have definetly set the bar I can't argue with that so I need to meet that requirement. This might mean that I might need to get motion capturing figured out. Oh boy! I wonder if I can do that with Isaac.</p>
</li>
</ul>
<h4>2/24/2026</h4>
<ul>
<li><p>Dang does time fly. Other things have kept me away from this little project but I have some time now.</p>
</li>
<li><p>Moved my repo to github and tried to use git submodule to keep px4 as a dependency. Has turned out to be very annoying. Currently trying to get px4 to build right now.</p>
</li>
<li><p>I first had to update <code>px4_add_*.cmake</code> file to use <code>Wno-double</code> instead of <code>Wdouble</code>.</p>
</li>
<li><p>Okay so I had to nuke my old <code>.venv-px4</code> cause it wasn't being able to find the right python3</p>
</li>
<li><p>Great got it working again, only took like 3 hours...</p>
</li>
<li><p>Going to set out to do a few things I mention back on 2/12/26 tomorrow.</p>
</li>
<li><p>Also seems like running <code>make px4_sitl gz_x500</code> doesn't automatically open up the simulator, so we need to open up a third terminal and use</p>
</li>
</ul>
<h4>2/25/2026</h4>
<ul>
<li><p>Well after our whole refactoring yesterday, the simulator still isn't showing up properly. I see the console but not the the Gazebo Simulator.</p>
</li>
<li><p>I may have found some easier instructions on how to get this project setup next time. <a href="https://docs.px4.io/main/en/dev%5C_setup/dev%5C_env%5C_mac">https://docs.px4.io/main/en/dev\_setup/dev\_env\_mac</a></p>
</li>
<li><p>Based on that documentation there is this script <code>./Tools/setup/macos.sh --sim-tools</code> which should install anything I may have missed.</p>
</li>
<li><p>Im going to be pretty cheesed if this works. Sometimes I need to just find the documentation ya know. Anyway I learned a little bit about <code>Git</code>, <code>venv</code>, and <code>symbolic links</code> which is pretty nice so growth none the less.</p>
</li>
</ul>
<h4>2/26/2026</h4>
<ul>
<li><p>Okay so I sorta lied. Not really, I just thought I had done something I hadn't. So the simulator still isn't running and now I can't even get the console to work properly. Now I am having Codex take a look at it so I don't waste more of my after noon working on getting a damn simulator to work on my Mac. I have better things to do.</p>
</li>
<li><p>Okay looks like Codex was able to do it. Took a while and it definitely had to do some messing with but it looks to be running again.</p>
</li>
<li><p>Okay lets see where we are in terms of architecture. Oh yeah I was looking into this research paper <a href="http://arxiv.org/abs/2601.15222">monoracer</a> . I should ask chat to read it and help me try and reproduce a similar architecture.</p>
</li>
</ul>
<h4>2/27/2026</h4>
<ul>
<li>I think Chat and I have come up with a pretty good architecture for now. I think the best thing we can do is get an adapter working and have the virtual drone fly. That way we can learn what works and what doesn't for an adapter. Also making is that we don't have to change anything in the code to switch between simulators would be the end goal however we are not there yet.</li>
</ul>
<h4>2/28/2026</h4>
<ul>
<li><p>Working on getting this virtual pony to fly</p>
</li>
<li><p>Okay I need to take a step back cause Codex is starting to go crazy over here with the architecture. I need to get my barrings on what exactly the input and output should be for this project.</p>
</li>
</ul>
<h4>3/1/2026</h4>
<p>Okay so this a quick overview of what we will be getting:</p>
<p>INPUT:</p>
<ul>
<li><p>image</p>
</li>
<li><p>position</p>
</li>
<li><p>velocity</p>
</li>
<li><p>orientation</p>
</li>
<li><p>IMU - accelerometer</p>
</li>
<li><p>IMU - gyroscope</p>
</li>
</ul>
<p>PROCESS:</p>
<ul>
<li>neural network</li>
</ul>
<p>OUTPUT:</p>
<ul>
<li><p>roll</p>
</li>
<li><p>pitch</p>
</li>
<li><p>yaw</p>
</li>
<li><p>throttle</p>
</li>
</ul>
<p>So basically:</p>
<p><strong>Coming in:</strong> Camera + Pose + Velocity</p>
<p><strong>Processing:</strong> Neural network decides how to tilt.</p>
<p><strong>Going out:</strong> Roll, Pitch, Yaw, Throttle</p>
<ul>
<li>ChatGPT gives a pretty good example of what we might see as an input.</li>
</ul>
<pre><code class="language-plaintext">One concrete “frame” example:

At `t_cam = 12.400s`:

**Incoming**
- Image shows gate center offset: `dx=+0.18, dy=-0.12`
- Velocity: `v = [6.0, 0.2, 0.0] m/s`
- Orientation: (quat) `q = [0.98, 0.01, 0.10, 0.15]`

- IMU window last 100ms:
	- gyro_mean `[0.02, -0.01, 0.35]`
	- accel_mean `[0.30, 0.05, -9.50]`

**Policy outputs**
- roll `+0.30`, pitch `+0.20`, yaw `+0.10`, throttle `0.64`

**Outgoing**
- same 4 commands (converted/scaled by adapter)
</code></pre>
<ul>
<li><p>Okay sick we got the propellers to spin however I keep getting arming issues and etc.</p>
</li>
<li><p>Okay we got something working. That's progress. The drone can take off and fly. Simply little script does it with the help of chat. Seems pretty straight forward.</p>
</li>
<li><p>I need to read through the docs on set_attitude and do some learning on Hz and and mavlink commands.</p>
</li>
<li><p>Okay so stop the timer. It took 11 days or just about 40 hours to get the simulator working and the drone to fly. I could have probably done this on day 5 but I decided to refactor and start working on architecture for a little while. Anyway its nice that it didn't take too long. I was able to use ChatGPT to iterate through different versions of what works and what doesn't so now I have a really good example of what needs to happen to make commanding this drone to work. This will be a great reference when building my models and architecture.</p>
</li>
<li><p>Since its march I think it should make sense to get a good underlying system for sending and retrieving messages. I think I will make data classes for input and outputs and make sure they implement base classes that have methods that do quarternion conversion and Frame conversions which should make my life much easier.</p>
</li>
<li><p>Time to call it a night.</p>
</li>
</ul>
<h4>3/2/2026</h4>
<ul>
<li>Okay so we got our drone to fly. Now I need to understand how its flying. I will need to do a bit of learning today and tomorrow to make sure it all make sense.</li>
</ul>
<p><strong>Mavlink Learnings</strong>:</p>
<ul>
<li><p>Mavlink is the protocol used between our python code and PX4 which is the controller and model in the simulation.</p>
</li>
<li><p>Messages are defined by xml files and are also known as <em>dialects</em></p>
</li>
<li><p>Px4 is speaking <code>Mavlink version 2</code> we see this when we run <code>mavlink status</code></p>
</li>
<li><p>The dialect is determined by the <code>pymavlink</code> which I believe is <code>pymavlink/dialects/v20/ardupilotmega.py</code> that means our <code>pymavlink</code> install is currently using the <code>ardupilotmega</code> dialect module as the generated Python definitions for messages/fields. That does <strong>not</strong> mean our vehicle is ArduPilot. It just means pymavlink is using that generated module as the message definitions</p>
</li>
<li><p><a href="%5Bhttps://docs.px4.io/main/en/middleware/mavlink.html%5D(https://docs.px4.io/main/en/middleware/mavlink.html)">PX4 telemetry basics</a> &amp; <a href="%5Bhttps://docs.px4.io/main/en/advanced/offboard.html%5D(https://docs.px4.io/main/en/advanced/offboard.html)">Offboard control examples (Python)</a> These cover exactly what we’re doing with <code>SET_POSITION_TARGET_LOCAL_NED</code> and <code>SET_ATTITUDE_TARGET</code>.</p>
</li>
</ul>
<p><strong>Streaming concepts</strong></p>
<p>Control stream</p>
<ul>
<li><p><strong>50–100 Hz</strong> setpoints (PX4 requires &gt;2 Hz, but racing needs faster for control)</p>
</li>
<li><p>Use <em>one</em> setpoint type consistently per run:</p>
</li>
<li><p><code>SET_POSITION_TARGET_LOCAL_NED</code> (velocity mode) for simple racing baseline</p>
</li>
<li><p>or <code>SET_ATTITUDE_TARGET</code> (attitude+thrust) for more direct control</p>
</li>
<li><p>don’t mix unless you’re doing the keepalive trick on purpose</p>
</li>
</ul>
<p>Telemetry stream</p>
<ul>
<li><p>30–100 Hz (depends what you subscribe to / what PX4 is sending)</p>
</li>
<li><p>You should treat telemetry as “latest sample wins”:</p>
</li>
<li><p>a background receiver updates <code>latest_state</code></p>
</li>
<li><p>the controller reads <code>latest_state</code> each tick</p>
</li>
</ul>
<p>Camera stream</p>
<ul>
<li><p>30–60 FPS typical</p>
</li>
<li><p>Same approach: background thread decodes frames, stores latest</p>
</li>
</ul>
<p>Therefore our architecture has 2–3 loops</p>
<ol>
<li><p>Rx loop (telemetry)</p>
<ul>
<li><p>blocks on <code>recv_match()</code></p>
</li>
<li><p>updates thread-safe <code>latest_telemetry</code></p>
</li>
</ul>
</li>
<li><p>Camera loop</p>
<ul>
<li><p>decodes frames</p>
</li>
<li><p>updates <code>latest_frame</code></p>
</li>
</ul>
</li>
<li><p>Control loop (fixed Hz) - reads latest inputs (frame + telemetry) - runs policy - sends setpoint - sleeps to maintain rate</p>
</li>
</ol>
<p>The control loop should be the only thing that “owns” timing.</p>
<h4>3/3/2026</h4>
<ul>
<li><p>Okay now that I have a clearer idea of of streaming I think we can look at the Mono-racer research and as ourselves what methods are available for us to use and possibly understand their streaming process and understand their differences.</p>
</li>
<li><p>Lets look over MonoRacers methods with our new found knowledge.</p>
</li>
<li><p>Hmm still a lot of this I don't understand. EKF, PnP, QuAdGate corner extraction, GateNet segmentation.</p>
</li>
<li><p>What I can understand now is that they probably had something like 6 asynchronoous loops running at different Hz sharing some state to perform operations. I wrote some notes on my ipad so I won't pollute the blog here but I think I have a good idea of what goes on in each loop at a high level. I think tonight I need to be clear on what the input and outputs are going to be and just write something up that works.</p>
</li>
<li><p>Something really important that we need to look out for when they publish their module is whether they are using a step-based API or a push-based API.</p>
</li>
</ul>
<h4>3/5/2026</h4>
<ul>
<li><p>Alright took a couple days off. Time to get back to work.</p>
</li>
<li><p>Just got confirmation that we will be getting most of the simulation and API stuff on March 19th which give me only a couple days to get this foundation setup. Since programming takes time, I won't be writing much here unless I think it makes sense to for me to add for posterity.</p>
</li>
<li><p>Okay in trying to write this adapter I've realized I've needed to basically build the underlying architecture and i've built up too many requirements in my head to keep track of. Time to write a little design spec for myself that I can update while I work on this code.</p>
</li>
</ul>
<h4>3/6/2026</h4>
<ul>
<li>Okay time to glance through the design spec a little more and we should be able to get started on making this thing work without chatGPT. Starting small of course. I had chat gpt give a few structural pointers and I think we have come up with something I could adapt for my goals. First thing first is getting the adapter to work properly and getting this drone to fly.</li>
</ul>
<h4>3/7/2026</h4>
<ul>
<li>Okay so in order to get the adapter to work properly I need to get a high level understanding of what the control loop and runner are going to be doing. I have been writing psuedo code for what I will need and I realized that a drone class will be very helpful for modularity and making the running code very readable. I think it will make sense if the drone takes most of the objects we will be using ie modules, sharedState, and adapter.</li>
</ul>
<h4>3/8/2026</h4>
<ul>
<li><p>Alright, we are making good process. I think I have an okay architecture right now that should at least let me test a few unfinished modules out using a gazebo adapter. The question is whether the abstractions I took care to create will end up making adapting this code to other simulators and drones easy-ish. We will cross that bridge when we get there. I probably didn't have to do all this abstraction however, for readability purposes I decided that putting in the effort would way off later for my sanity. One part that I really wanted to get right was the multiple threads running at the same time. I have never worked with multiple threads like this so I have no idea how their characteristics will influence the Autonomy Stack during flight. I have some guesses where issues will appear with thread loops running at different Hz but I could just be making it up. I should look into this at some point.</p>
</li>
<li><p>Alright sick, we got all of the code written out. Writing the adapter was quite easy given the fact that we had written a test script that essentially had all of the functions we need like sending attitude data, request_arm, etc.. This will probably be MO when making an adapter for other simulators as well 1. test script 2. transfer to adapter.</p>
</li>
<li><p>Super excited to test this out. Tomorrow is my Birthday so I may or may not have enough to do so but if I do I will most likely be debugging random issues. I expect to have to wrangle with python syntax and and timing issues. I added a lot of timing functionality based on what chat had recommended to me but now that I have most of it written out I need to do some investigating into the best solution.</p>
</li>
<li><p>Anyway with this written I think we completed out second goal which was <strong>Create a system architecture for Albatross</strong> in total it took around 1 month of development to get to this point. not sure how many hours but 17 days x 3 hours per day is 57 hours give or take. Not too bad. A weeks worth of work and some change.</p>
</li>
<li><p>When the competition comes around I'll have to put in more elbow grease. I hope the work that I have put it now will help me focus on the main goal of the competition which is to create an autonomy stack for a drone. This will no doubt be way harder to get right and will most likely require me to rewrite some parts of my architecture but hopefully not too much.</p>
</li>
<li><p>I think after getting a simple take off and fly forward working with my control loop and new architecture, I'll start working on getting adapters created for Issac and AirSim. I will try to make this my main goal for the week. The competition really starts on March 19th which is when we get the API from Andruil. So that gives me about 10 days to get familiar with Issac and AirSim which may or may not be helpful when training my Autonomy Stack.</p>
</li>
</ul>
<h4>3/9/2026</h4>
<ul>
<li><p>I really like this project a lot. Its the evening of my birthday and I can't help but sit down and work on it. There's just something about playing music and losing myself in designing and coding.</p>
</li>
<li><p>Yesterday I was able to connect all of the layers of my Autonomy stack so today I'll be mostly debugging. I will add some updates here if I think them important.</p>
</li>
<li><p>Nice thing about this project log is if I am ever curious about the code I wrote I can always just look at the commits along with each of these logs.</p>
</li>
<li><p>Okay so most of the fixes I did were import fixes and some cleaning up. The script runs no problem but now the drone won't fly. The drone gets armed but it won't take off. I know my environment is working cause the old test script I wrote still works.</p>
</li>
</ul>
<h4>3/10/2026</h4>
<ul>
<li>This is what I get from my new architecure from PX4 Logs:</li>
</ul>
<pre><code class="language-bash">pxh&gt; INFO  [mavlink] partner IP: 127.0.0.1
INFO  [commander] Armed by external command
INFO  [tone_alarm] arming warning
INFO  [commander] Disarmed by external command
INFO  [tone_alarm] notify neutral
INFO  [logger] closed logfile, bytes written: 10334763
</code></pre>
<ul>
<li>And this is what I get from the test script code:</li>
</ul>
<pre><code class="language-bash">INFO  [commander] Armed by external command
INFO  [tone_alarm] arming warning
INFO  [logger] Start file log (type: full)
INFO  [logger] [logger] ./log/2026-03-11/05_21_22.ulg
INFO  [logger] Opened full log file: ./log/2026-03-11/05_21_22.ulg
INFO  [commander] Takeoff detected
WARN  [commander] Disarming denied: not landed
INFO  [tone_alarm] notify negative
WARN  [failsafe] Failsafe activated
INFO  [navigator] RTL: start return at 31 m (30 m above destination)
INFO  [tone_alarm] battery warning (fast)
INFO  [navigator] RTL: land at destination
INFO  [commander] Landing detected
INFO  [commander] Disarmed by landing
INFO  [tone_alarm] notify neutral
INFO  [logger] closed logfile, bytes written: 14709756
</code></pre>
<ul>
<li>What is super weird is that if I try to run my new architecture directly after running my test script, the drone flies perfectly.</li>
</ul>
<pre><code class="language-bash">INFO  [commander] Armed by external command
INFO  [tone_alarm] arming warning
INFO  [logger] Start file log (type: full)
INFO  [logger] [logger] ./log/2026-03-11/05_32_18.ulg
INFO  [logger] Opened full log file: ./log/2026-03-11/05_32_18.ulg
INFO  [commander] Takeoff detected
WARN  [commander] Disarming denied: not landed
INFO  [tone_alarm] notify negative
WARN  [failsafe] Failsafe activated
INFO  [navigator] RTL: start return at 76 m (76 m above destination)
INFO  [tone_alarm] battery warning (fast)
INFO  [navigator] RTL: land at destination
INFO  [commander] Landing detected
INFO  [commander] Disarmed by landing
INFO  [tone_alarm] notify neutral
INFO  [vehicle_magnetometer] 0 (197388) EST:0 offset: [0.000, 0.000, 0.000]-&gt;[0.003, -0.004, 0.002] (full [0.INFO  [logger] closed logfile, bytes written: 28366799
</code></pre>
<ul>
<li>I think I found the problem. Syntax Syntax Syntax.</li>
</ul>
<pre><code class="language-plaintext"># runner.py
...
self.drone.offboard &lt;-- do you see the problem here?
...
</code></pre>
<ul>
<li><p>Wasn't actually calling the offboard function. The test script was setting this up for the new architecture. Silly mistake but it didn't take me too long to find it so I'm a happy camper.</p>
</li>
<li><p>Okay now that we got this thing flying, what should I clean up.</p>
</li>
<li><p>Right now I have no idea of telling if my drone is actually doing what I want it to. Sure it gets up and flies away but I don't know if its doing what I intended. For instance I don't tell it to rotate but some how it ends up making 90 degrees turn and then flies upward. Why 90 degrees? I wonder what the standardized way for logging out flight data and how I can make it easier to understand.</p>
</li>
<li><p>Chat says that since I am setting the Yaw to be 0 it could be sending the drone to NED yaw 0 which I guess the drone doesn't start off facing. I will need to read through the docs to understand this more. I will also need to make sure that this is standard for other simulators or things could get complicated.</p>
</li>
<li><p>I guess now it makes sense to set up an extendable testing infrastructure.</p>
</li>
<li><p>Also if you want to learn more about what the architecture looks like at this stage, I had copilot create some documentation outlining it. [[Albatross Autonomy Stack v1]]</p>
</li>
</ul>
<h4>3/11/2026</h4>
<ul>
<li><p>Before going crazy and cleaning up the code too much, I think its best I start finalizing what models I will need and what modules they should go into. The goal is that each module performs a specified task.</p>
</li>
<li><p>Time to do some more research.</p>
</li>
<li><p>...<em>Couple Hours Later</em>...</p>
</li>
<li><p>Wow, I just got some great advice from ChatGPT using its extended thinking. I have a pretty clear idea about what modules I will need to create now, what I need to refactor now to make those modules work and what phases I should build things in. All of this will be added to a separate document for me to reference later. Truly some great advice.</p>
</li>
</ul>
<h4>3/12/2026</h4>
<ul>
<li><p>Today I have just been reading through all of the advice Chat gave me and trying to piece together a good to do list for myself. I also want to do my best to understand why I am implementing everything. I want to understand what's happening.</p>
</li>
<li><p>I started writing a Albatross V2 - Design Specification which should come in handy when I start developing. Its mainly based on Chatgpts advice with my own questions and thoughts sprinkled in so that I can revisit them during development.</p>
</li>
</ul>
<h4>3/13/2026</h4>
<ul>
<li><p>Started working a little late so I am a little tired. Going to try and walk through the new architecture and see if there is anything I am missing.</p>
</li>
<li><p>I am sort of slow walking through chatGPTs proposal and making notes of anything I don't understand or implementation examples that are missing core ideas mentioned in the document.</p>
</li>
</ul>
<h4>3/14/2026</h4>
<ul>
<li>Just reviewing the new architecture to make sure everything looks good.</li>
</ul>
<h4>3/16/2026</h4>
<ul>
<li>Took two days to rest up a little. I like to think that breaks are healthy. The API should be coming out this Thursday so I have to get moving on implementing my new architecture. I think I need to do a little review on a few things before getting started, but I definitely want to get started today or tomorrow.</li>
</ul>
<h4>3/19/2026</h4>
<ul>
<li><p>Had a few things come up, back to work. Today the design spec came out. Good news! They want to use Mavlink with UDP SITL which is exactly what our first adapter is built to handle. Got super lucky there.</p>
</li>
<li><p>Before going off the rails I think I'll read through specification first and get an idea of what needs to change in the architecture. Based on my brief look through I seem to be on the right track.</p>
</li>
</ul>
<p><strong>What the spec tells us:</strong></p>
<ul>
<li><p>communication interfaces between contestant software and the simulator</p>
</li>
<li><p>control input requirements</p>
</li>
<li><p>telemetry interfaces</p>
</li>
<li><p>vision data interfaces</p>
</li>
<li><p>simulation timing and performance constraints</p>
</li>
<li><p>virtual race environment definition</p>
</li>
<li><p>qualification run requirements</p>
</li>
</ul>
<p>There are a few things that caught my eye</p>
<ol>
<li><p>Sections 4.1-4.3 are about MAVLINK. We basically have the adapter close to perfect and what we might need for this competition which is great.</p>
<ul>
<li><p>Although there are things I am unfamiliar with like:</p>
<ul>
<li><p>SET_POSITION_TARGET_LOCAL_NED</p>
</li>
<li><p>TIMESYNC</p>
</li>
<li><p>ODOMETRY</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Section 4.4 Timing</p>
<ul>
<li><p>Physics simulation rate: 120hz <strong>&lt;-- What does this tell us exactly? Telemetry rate?</strong></p>
</li>
<li><p>Recommended command rate: 50-120 Hz <strong>&lt;-- This is signifacantly lower than my 800hz goal lol</strong></p>
</li>
<li><p>Minimum heartbeat rate: 2hz <strong>&lt;-- I am not sure if we are implementing this properly atm</strong></p>
</li>
</ul>
</li>
<li><p>Section 4.5 Telemetry</p>
<ul>
<li><p>vehicle attitude <strong>&lt;-- we will be getting this using ATTITUDE</strong></p>
</li>
<li><p>orientation <strong>&lt;-- I think this will come from where? IMU?</strong></p>
</li>
<li><p>linear velocities <strong>&lt;-- This will come from the ATTITUDE as well I believe</strong></p>
</li>
<li><p>system status flags <strong>&lt;-- where is this coming from?</strong></p>
</li>
<li><p>simulator navigation reference data <strong>&lt;-- What does this mean?</strong></p>
</li>
</ul>
</li>
<li><p>Section 4.7 Software-in-the-Loop Bridge: The simulator provides a low-latency UDP SITL bridge enabling external AI controllers to exchange telemetry and control commands. &lt;<strong>-- What do they mean by external AI controllers? Is this just referencing the normal setup for reading and sending controls and telemetry or is this something else entirely.</strong></p>
</li>
<li><p>Section 5 is all about the environment which is really important.</p>
</li>
<li><p>Section 5.1 Runtime Environment. We get to choose what python environment we get to use. interesting.</p>
</li>
<li><p>Section 5.2 Client Responsibilities</p>
<ul>
<li><p>Establish MAVLink communication (GOOD TO GO)</p>
</li>
<li><p>maintain heartbeat messages <strong>&lt;-- Not super confident I understand this in our current code base.</strong></p>
</li>
<li><p>Send control commands</p>
</li>
<li><p>process telemetry data</p>
</li>
<li><p>process vision stream data</p>
</li>
</ul>
</li>
<li><p>5.3 Intended Control Architecture.</p>
<ul>
<li><p>Vision + Telemetry &lt;-- (platform and vision adapters take of this)</p>
</li>
<li><p>Perception</p>
</li>
<li><p>Planning</p>
</li>
<li><p>Control</p>
</li>
<li><p>Pilot Commands</p>
</li>
<li><p>Stabalized Controller <strong>&lt;-- Is this refereing to our safe_guard policy?</strong></p>
</li>
</ul>
</li>
<li><p>Section 6 Example Control Session</p>
<ul>
<li>This should be easy to implement using an specific competition orchestrator.</li>
</ul>
<ol>
<li><p>Client initializes MAVSDK</p>
</li>
<li><p>Client connects to simulator endpoint</p>
</li>
<li><p>Simulator transmits HEARTBEAT</p>
</li>
<li><p>Client streams control commands</p>
</li>
<li><p>Simulator applies commands</p>
</li>
<li><p>Telemetry and vision streams returned</p>
</li>
</ol>
</li>
<li><p>Section 7. Compliance. NO HUMAN INTERACTION DURING TIMED RUNS.</p>
</li>
<li><p>Section 8. Round One Qualification Phase</p>
<ul>
<li><p>Round One verifies that contestants software can successfully navigate the racecourse.</p>
</li>
<li><p>Start Gate intermediate gates and finish gates</p>
</li>
<li><p>Maximum Run Duration is 8 minutes. The difficulty of this requirement will depend on how many gates there are and how fast my drone must be able to fly during this round.</p>
</li>
</ul>
</li>
</ol>
<p>I asked chat how this might change our current architecture and plan and its answer is [[Architecture Review based on Tech Spec|here]]</p>
<p><strong>Module Refactor + SharedState Update per Tech Spec:</strong></p>
<ul>
<li><p>The new architecture should still be green to go.</p>
</li>
<li><p>Here is the first thing we need to do, update how modules work. Reason is because right now our modules are all in one place and the idea is that these modules should be used by other services such as a training and replay service. This won't be possible if they are being used soley as a part of the racing pipeline. Moving the logic for each module out of the core/ directory into a library directory will help with this division for training and replay purposes.</p>
</li>
<li><p>The Plan:</p>
</li>
</ul>
<ol>
<li><p>Add all necessary files I think I will need for this new architecture</p>
</li>
<li><p>Move logic out of the control_module.py so that it becomes a thin wrapper meant to direct to the actual logic somewhere else. This can also be paired with updating the sharedstate object and using the newly released design spec.</p>
</li>
<li><p>Update the current module_base.py too</p>
</li>
</ol>
<p><strong>Replay Logging and Replay Execution:</strong></p>
<ul>
<li><p>Also something really important I learned is that logging is also used for replay. This will probably be the second thing I implement.</p>
</li>
<li><p>Why would we want replay?</p>
<ul>
<li><p>You want replay so you can do things like:</p>
<ul>
<li><p>run one sim flight once</p>
</li>
<li><p>save all sensor inputs and module outputs</p>
</li>
<li><p>later rerun just perception on the same frames</p>
</li>
<li><p>later rerun estimation on the same IMU + detections</p>
</li>
<li><p>later compare old policy vs new policy on the same observations</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>and so replay logging should let us answer:</p>
<ul>
<li><p>what did the sensors produce?</p>
</li>
<li><p>when did they produce it?</p>
</li>
<li><p>what did each module see?</p>
</li>
<li><p>what did each module output?</p>
</li>
<li><p>what command got sent?</p>
</li>
</ul>
</li>
<li><p>You might wonder if we could use a global tick to keep track of what was going on at each tick but this is essentially difficult because we have multiple threads and a single global tick could become misleading. We currently have platform telemetry pump, camera frame pump, perception thread, estimation thread, control thread, command stream thread etc. these do not all run in lock step.</p>
</li>
<li><p>Now a tick for each thread will still be useful since you we would be able to log</p>
<ul>
<li><p>module name</p>
</li>
<li><p>local tick index</p>
</li>
<li><p>tick start time</p>
</li>
<li><p>tick end time</p>
</li>
<li><p>input ages</p>
</li>
<li><p>output sequence</p>
</li>
<li><p>deadline miss yes/no</p>
</li>
</ul>
</li>
<li><p>however replay itself will still be driven mostly by timestamps and event order.</p>
</li>
<li><p>There are two ways to use the replay once we have the logs for a module after a flight run.</p>
<ol>
<li><p>Mode 1: Fast-as-possible replay.</p>
<ol>
<li>Used for offline testing</li>
</ol>
<ul>
<li><p>read next logged event</p>
</li>
<li><p>publish it immediately</p>
</li>
<li><p>run modules as fast as possible.</p>
</li>
</ul>
<ol>
<li>This is best for:</li>
</ol>
<ul>
<li><p>debugging logic</p>
</li>
<li><p>unit/integration tests</p>
</li>
<li><p>comparing versions</p>
</li>
</ul>
</li>
<li><p>Mode 2: Real-time replay</p>
<ol>
<li>Used for timing validation</li>
</ol>
<ul>
<li><p>preserve original event timing gaps</p>
</li>
<li><p>sleep according to logged timestamps</p>
</li>
<li><p>simulate orginal cadence</p>
</li>
</ul>
<ol>
<li>This is best for:</li>
</ol>
<ul>
<li><p>Checking latency behavior</p>
</li>
<li><p>testing freshness logic</p>
</li>
<li><p>observing thread behavior close to live execution.</p>
</li>
</ul>
</li>
</ol>
</li>
<li><p>Here is a [[Modules Implementing Replay Logging#10) What exactly should modules log for replay/debugging|list]] of modules that will need replay/debugging implemented. I will of course start off with the control_module.py to test the overall logging and replay system. I also had questions about the difference between a sequence and a local tick and chat answered [[logging and replay#What is the difference between a lock tick and a sequence?|here]]</p>
</li>
<li><p>Side note, when we are implementing a monotonic timer we have two options:</p>
<ul>
<li><code>monotonic()</code> and <code>per_counter_ns()</code></li>
</ul>
</li>
<li><p>Both are monotonic timers but perf is newer semantically for benchmarking while monotonic is the clearer API semantically for deadlines/timeouts/scheduling. More details from chat here about using either one. End of the day we should probably choose one to keep the code consistent and clear.</p>
</li>
<li><p>We'll use it for these things:</p>
<ul>
<li><p>module tick timing</p>
</li>
<li><p>record ordering within a run</p>
</li>
<li><p>freshness checks</p>
</li>
<li><p>replay timing</p>
</li>
<li><p>measuring compute durations</p>
</li>
</ul>
</li>
<li><p>To keep track of human time (as in wall clock) we should use <code>time.time()</code></p>
</li>
<li><p>More information about using wall clock and the performance counter can be found [[Using the wall time and performance counter|here]]</p>
</li>
</ul>
<h4>3/21/2026</h4>
<ul>
<li><p>Past two days I have been traveling so haven't had much time to sit down and work. Making time for fun things like this require time that I don't always have. Consistency is more fun when its challenging.</p>
</li>
<li><p>There are a few things I want to jot down right now that I will need to come back to. After reading through chat's advice after reading the specification [[Architecture Review based on Tech Spec|here]] it mentions that the command loop have a cap of running at 120Hz which is very low. It also mentions something called a Watchdog which I am not sure its purpose. I also need to look into the importance of the TimeSyncing and how to use it my advantage. I will also need to look into "Stabilized Controller" which is new vocabulary for a layman such as myself. This may or may not be something I have planned, but its a module so I can move forward with coding.</p>
</li>
<li><p>Implementing V2 now.</p>
</li>
<li><p>Okay I actually need help getting a clear SharedState written up based on the spec. [[SharedData Revamp|here]]</p>
</li>
<li><p>Okay nice, I think we cleanly refactored the sharedstate and command classes. shared data will have base_types which will be used either as a LatestValue or RingBuffer Topic. LatestValue and RingBuffer Topic will abstract away locks and the complexity of publishing, getting freshness, and storing sequence information for future logging and replay purposes.</p>
</li>
<li><p>We also updated the types for commands by adding a safe_action_type.py as another layer along side action_type.py as an internal version of what will become the command_type.py.</p>
</li>
<li><p>Its getting late so I am going to call it there. Tomorrow I would like to start getting the control_module revamped keeping the logging and replay in mind which may or may not get worked on at the same time.</p>
</li>
</ul>
<h4>3/22/2026</h4>
<ul>
<li><p>Okay time to work on the control_module with the SharedState Refactor in mind. Right now I am following this guide I got from chatGPT [[How to refactor using existing architecture#Example <code>control_module.py</code>|here]].</p>
</li>
<li><p>Didn't get too much work done. Had to stop and do some vacation stuff.</p>
</li>
</ul>
<h4>3/24/2026</h4>
<ul>
<li><p>Alright we are back. I had my nice 4 day vacation which really made it hard to focus on this project. Not to mention the headache of using one screen for 4 windows.</p>
</li>
<li><p>My schedule is so limited I really need to be consistent so that I don't have to go through an entire project day ramping back up. Thankfully there shouldn't be too much else getting in the way as far as I can tell.</p>
</li>
<li><p>Last I remember I was starting to work on moving the core logic for the control_module.py out into a policy library. I remember getting a little stuck cause I had already created a pretty good shared data models but in order for the controller to work I need an observation that matches the type of data type but I haven't made it yet.</p>
</li>
<li><p>I also started getting really confused on what the purpose of the observation is. I had chat make a dumb heuristic policy and even that had me scratching my head. So I guess I need to do a little bit of learning before diving deeper into implementation. Through out this process I need to keep in mind the logging replay.</p>
</li>
</ul>
<p><strong>What an Observation is:</strong></p>
<p>An observation is a compact summary of the world that the controller consumes.</p>
<p>It is not:</p>
<ul>
<li><p>raw MAVLink Telemetry</p>
</li>
<li><p>Raw Camera Pixels</p>
</li>
<li><p>Raw IMU History It is:</p>
</li>
<li><p>the "few numbe rthe policy needs right now" For our current design, that means numbers like:</p>
</li>
<li><p><code>bearing</code>: how far left/right the next gate is in the image</p>
</li>
<li><p><code>elevation</code>: how far up/down the gate is</p>
</li>
<li><p><code>scale</code>: how large the gate appears, as a proxy for distance</p>
</li>
<li><p><code>yaw_error</code> how rotate the gate looks</p>
</li>
<li><p>derivatives of those values</p>
</li>
<li><p>confidence So the flow would be:</p>
</li>
<li><p>telemetry + vision → estimation logic → Observation(vec, mask, valid) → control policy</p>
</li>
<li><p>That is why our <code>ControlModule</code> reads <code>shared_state.estimation.observation</code>.</p>
</li>
<li><p>Eventually we will need that observation to come from a real estimation script but for now I need to do a little end-to-end testing with this new setup to make sure I can confidently start building more.</p>
</li>
<li><p>For now I will create a temporary module called <code>DummyObservationModule</code> which will read one or two easy topics like attitude construct a valid observation and publish it at a fixed rate. for now we can make the observation show that the gate is straight ahead at all time to keep this relatively deterministic.</p>
</li>
<li><p>This will let us verify that our topics work, module scheduling works, <code>ControlModule</code> can read observations, heuristic policy generates actions, safely converts action to commands and command loop sends them.</p>
</li>
</ul>
<p>It should only prove that the framework dataflow works:</p>
<ol>
<li><p>adapters publish sensor topics</p>
</li>
<li><p>dummy module publishes observation</p>
</li>
<li><p>control publishes policy action</p>
</li>
<li><p>safety publishes command</p>
</li>
<li><p>adapter sends command</p>
</li>
<li><p>logs show healthy rates and freshness</p>
</li>
</ol>
<p><strong>What our Heuristic Policy is doing</strong></p>
<ul>
<li><p>Our heuristic policy is basically a hand-written “fly toward the gate” controller.</p>
</li>
<li><p>So the whole policy is:</p>
<ul>
<li><p>line up horizontally</p>
</li>
<li><p>line up rotationally</p>
</li>
<li><p>trim height</p>
</li>
<li><p>move forward when alignment is decent</p>
</li>
</ul>
</li>
<li><p>Its already late so I need to pause here but tomorrow the goal is to finish understanding the observation module and then test everything out. Then the next goal is to start getting a logging and replay working for the Control_Module.py and working on understand how something like that would work.</p>
</li>
</ul>
<h4>3/25/2026</h4>
<ul>
<li><p>Got about 2 hours to get some real work done here. We just finished looking through the main functionalities that come from the <code>dummy_observation_module.py</code>.</p>
</li>
<li><p>Okay just for self reference, the new module_type (which is a base type inherited by all modules) by default defines tick, create_thread, and a <em>run_loop</em>. The run_loop method is a private method used by the create_thread method to make sure we don't have to rewrite too much of the thread logic.</p>
</li>
</ul>
<ol>
<li><p><code>create_thread</code> is called by <code>pipeline</code> to start up all modules (except for the Control and SafetyModule)</p>
</li>
<li><p><code>create_thread</code> calls <code>_run_loop</code> which in turn calls <code>tick</code>.</p>
</li>
<li><p><code>tick</code> is implemented by the module and should route to the specified library with implementations for that module.</p>
</li>
</ol>
<ul>
<li><p>Okay I understand how the observation module works. Now I need to get a grasp of what's going on with the <code>HealthModule</code> stuff going on. I am assuming that it might be good to have the <code>_publish_health</code> as an method that can be added to other methods like <code>tick</code> to store state information. The problem is that I don't think i've created a ModuleHealth even though its referenced in <code>shared_data.py</code>. I will need to ask chat what this was meant to be and what an implementation would look like.</p>
</li>
<li><p>Anyway, another short day but good progress. Its getting late so calling it for tonight.</p>
</li>
</ul>
<h4>3/26/2026</h4>
<ul>
<li><p>Alright back to it. Time to learn about the ModuleHealth and what its doing and why we need it.</p>
</li>
<li><p>Okay so chat says that the ModuleHealth is basically our module's status report to the rest of the runtime. Its not part of the racing/control algorithm itself. It is part of the runtime supervision/ observability layer.</p>
</li>
<li><p>Each module is doing real-time work in its own loop. ModuleHealth Lets the system answer questions like:</p>
<ul>
<li><p>Is this module running at all?</p>
</li>
<li><p>is it running recently, or has it stalled?</p>
</li>
<li><p>is it getting stale inputs?</p>
</li>
<li><p>Is it currently healthy, stale, or faulted?</p>
</li>
<li><p>What was the last thing it complained about?</p>
</li>
</ul>
</li>
<li><p>So the purpose is:</p>
<ul>
<li><p>debugging</p>
</li>
<li><p>runtime monitoring</p>
</li>
<li><p>dashboard / prints</p>
</li>
<li><p>Watchdog logic</p>
</li>
<li><p>log/replay diagnostics.</p>
</li>
</ul>
</li>
<li><p>Without ModuleHealth, if something stops working you just see:</p>
<ul>
<li><p>The drone is not behaving right</p>
</li>
<li><p>maybe commands stopped making sense</p>
</li>
<li><p>maybe no detections are happing</p>
</li>
</ul>
</li>
<li><p>But we do not know which module is the problem</p>
</li>
<li><p>Although we said that ModuleHealth is not meant to part of the racing/control algorithm itself. we can use it to drive automatic safety behavior using WatchDogs.</p>
</li>
<li><p>“Stale” usually means:</p>
<ul>
<li><p>the module itself is still running</p>
</li>
<li><p>but its inputs are too old or invalid to produce good output</p>
</li>
</ul>
</li>
<li><p>Also ModuleHealth is not "health of the algorithm" its not saying. the controller is mathematically correct, the detector is accurate, the estimate is optimal. All its saying is "runtime module is functioning in an operational sense" which is the simplest thing we need working for the algorithm as a whole to work.</p>
</li>
<li><p>The important part now is how do we use the ModuleHealth information. For now printing the health of the modules seems fine for now, later we can have it so that a module prints its own heartbeat with some optimizations.</p>
</li>
<li><p>Okay I think I am getting really close to being able to test out this new Architecture. All I need to do is do my best to fix all of the imports and <code>_init_.py</code> files. I also need to make sure that the pump logic uses the new shared_state, topic system and make sure that each module is reading and writing using this new system. If a module isn't using this new version of the shared_state module then I should make as TODO.</p>
</li>
<li><p>After doing all that then I can start working on logging records for replay capabilities.</p>
</li>
<li><p>Cool, calling it a night.</p>
</li>
</ul>
<h4>3/27/2026</h4>
<ul>
<li><p>Started feeling a little sick this morning but really want to work on this so here we are. Going to work as much as I can without overworking myself. I want to use this weekend to finish this architecture revision.</p>
</li>
<li><p>Right now I am fixing imports and making sure that sharedstate is updated across the board since we updated it to use topics.</p>
</li>
<li><p>First thing that needed fixing was the main.py but it was a simple import fix</p>
</li>
<li><p>Next thing on my mind was fixing the GazeboPx4Mavlink Platform Adapter to use the updated version of the sharedState. Chat gave be some good advice [[architecture v2 gazebo_px4_sim_adapter.py|here]].</p>
</li>
<li><p>Okay things got a little bit more complicated. I asked chat to help me refactor and it started adding a whole bunch of stuff that I need to learn about because it mostly comes from our sharedstate update. There are a few ideas that are new to me.</p>
</li>
<li><p>Like what's difference between <code>pilot_command</code>, <code>command</code> and <code>command_tx_history</code>? Also what <code>heatbeat_rx</code>? What is <code>SystemStatusData</code> and how is this different from <code>HeartbeatData</code>? What is <code>heartbeat_tx</code>? and what is <code>timeSync</code> and why do we store it?</p>
</li>
</ul>
<p><code>pilot_command</code> is our internal representation of:</p>
<ul>
<li><p>roll</p>
</li>
<li><p>pitch</p>
</li>
<li><p>yaw rate/ yaw angle</p>
</li>
<li><p>thrust</p>
<ul>
<li>It is the desired pilot-style setpoint <code>command</code> is the command that the command loop.adapter should treat as the current official outbound command.</li>
</ul>
</li>
</ul>
<p>In a simple stack, <code>pilot_command</code> and <code>command</code> may be identical. For now we can think:</p>
<ul>
<li><p><code>pilot_command</code> = sematic layer name</p>
</li>
<li><p><code>command</code> = what the transport thread actually reads and sends</p>
</li>
</ul>
<p>Why keep both? Because later we may want a tiny extra step between them, such as:</p>
<ul>
<li><p>transport-specific conversion &lt;-- what the heck is this</p>
</li>
<li><p>command-rate resampling &lt;-- what the heck is this</p>
</li>
<li><p>offboard-loss fallback insertion &lt;-- what the heck is this</p>
</li>
<li><p>command validity checks &lt;-- what the heck is this</p>
</li>
</ul>
<p><code>command_tx_history</code> This is just a ring buffer of commands that were actually transmitted. We will use it for:</p>
<ul>
<li><p>debugging "what did we really send?"</p>
</li>
<li><p>replay/logging</p>
</li>
<li><p>rate checking</p>
</li>
<li><p>detecting repeated stale commands</p>
</li>
<li><p>comparing inteded command vs transmitted command</p>
</li>
</ul>
<hr />
<p><code>heartbeat_rx</code> vs <code>heartbeat_tx</code> These are just:</p>
<ul>
<li><p>received heartbeat</p>
</li>
<li><p>transmitted heartbeat</p>
</li>
</ul>
<p>Note these are both type <code>HeartBeatData</code></p>
<p><code>heartbeat_rx</code> The latest heartbeat you received <strong>from the simulator/autopilot side</strong>. We'll Use it to know:</p>
<ul>
<li><p>connection is alive</p>
</li>
<li><p>armed status</p>
</li>
<li><p>mode-ish status</p>
</li>
<li><p>system status-ish fields</p>
</li>
</ul>
<p><code>heartbeat_tx</code> The latest heartbeat <strong>your client sent outward</strong>.</p>
<p>Why store it?<br />Because the spec says the client is responsible for maintaining heartbeat messages, and it gives a minimum heartbeat rate of 2 Hz.</p>
<p>So storing <code>heartbeat_tx</code> lets us answer:</p>
<ul>
<li><p>are we actually sending them?</p>
</li>
<li><p>when did we last send one?</p>
</li>
<li><p>is our heartbeat loop stale?</p>
</li>
</ul>
<p>So:</p>
<ul>
<li><p><code>heartbeat_rx</code> = “what we heard from them”</p>
</li>
<li><p><code>heartbeat_tx</code> = “what we sent to them”</p>
</li>
</ul>
<hr />
<p><code>HeartBeatData</code> is the normalized representation of the MAVLink Heartbeat message itself It is about:</p>
<ul>
<li><p>link presence</p>
</li>
<li><p>base mode / custom mode</p>
</li>
<li><p>armed bit</p>
</li>
<li><p>autopilot/type identifiers</p>
</li>
<li><p>general heartbeat state So it answers:</p>
</li>
<li><p>did we receive a heartbeat?</p>
</li>
<li><p>what did the raw heartbeat say?</p>
</li>
</ul>
<p><code>SystemStatusData</code> This is our <strong>cleaner, normalized operational status view</strong> derived from one or more telemetry sources, often including heartbeat.</p>
<p>Why keep both?</p>
<p>Because sometimes you want:</p>
<ul>
<li><p>the raw-ish transport message (<code>HeartbeatData</code>)</p>
</li>
<li><p>and also a simplified internal status object (<code>SystemStatusData</code>)</p>
</li>
</ul>
<p>That separation is useful for debugging.</p>
<p>Example:</p>
<ul>
<li><p><code>HeartbeatData</code> says <code>base_mode=209</code></p>
</li>
<li><p><code>SystemStatusData</code> says <code>armed=True, offboard_enabled=False</code></p>
</li>
</ul>
<p>The second one is much easier for modules/watchdogs to use.</p>
<hr />
<p><code>TimeSyncData/timesync</code> The spec explicitly lists <code>TIMESYNC</code> as a supported MAVLink message.</p>
<p><strong>What it is</strong> It is timing information exchanged between endpoints so you can estimate:</p>
<ul>
<li><p>time offset</p>
</li>
<li><p>round-trip delay</p>
</li>
<li><p>maybe latency/jitter characteristics</p>
</li>
</ul>
<p><strong>Why store it?</strong> Even if you do nothing fancy with it at first, it is useful for:</p>
<ul>
<li><p>logging/debugging latency</p>
</li>
<li><p>understanding sim/client time relationship</p>
</li>
<li><p>later delay compensation</p>
</li>
<li><p>better replay analysis</p>
</li>
</ul>
<p>For example, if you later notice:</p>
<ul>
<li><p>observation age is weird</p>
</li>
<li><p>control is lagging</p>
</li>
<li><p>frame timestamps and telemetry timestamps do not line up well <code>timesync</code> data gives you a place to investigate that.</p>
</li>
</ul>
<p><strong>Do you need to use it immediately?</strong> No. You can store it now and ignore it at first. That is still worthwhile because:</p>
<ul>
<li><p>the spec names it explicitly</p>
</li>
<li><p>timing matters in your architecture</p>
</li>
<li><p>it is much easier to start logging it now than retrofit later</p>
</li>
</ul>
<hr />
<ul>
<li><p>A question I need answered at some point is what exactly are we supposed to be sending 2hz as a heartbeat? I don't think in our initial implementation we sent anything out other than our command which I guess may have been high enough to beat 2hz. Do I need to change anything here? Chat actually answered this [[architecture v2 gazebo_px4_sim_adapter.py#2. Heartbeat TX should be explicit|here]]. Seems like we should explicitly be sending heartbeats back to the simulator using <code>HearBeatData</code> and keeping track using `hearbeat_tx.</p>
</li>
<li><p>Okay I updated how we print hearbeat, systemstatus and positional information in the pipeline. I used [[Architecture v2 - Print Loop Refactor|this]] advice from chat.</p>
</li>
<li><p>I also created a <code>send_hearbeat</code> thread to meet that 2hz requirement.</p>
</li>
<li><p>I also updated the <code>send_command</code> thread to use our updated SharedState type. [[Architecture v2 - Command Loop Refactor|This]] is advice I got from chat.</p>
</li>
<li><p>Okay so I think we were able to update the platform adapter fairly well. All I need to do is ask chat to make me some types for the HeartBeatData, OdemetryData, TimeSyncData, and SystemStatusData.</p>
</li>
<li><p>From there I can start piecing everything together and mentally run through the whole process. I will add some comments in places where I need more context. Fixing imports is still something that needs to be done.</p>
</li>
<li><p>Again, after all this I will be testing the new architecture and then jumping to logging records and adding a replay capabilities.</p>
</li>
</ul>
<h4>3/28/2026</h4>
<ul>
<li><p>Not feeling sick thankfully. Okay so it running through the whole setup again.</p>
</li>
<li><p>Looks like we have everything setup well for another test. Im pretty nervous. I hope it won't be too much of a hassle to get it working.</p>
</li>
<li><p>Okay while I am working on this I started asking chat on the replay system we will be potentially implementing next.</p>
</li>
<li><p>Okay so for some reason our x86 terminal which should be running using rosetta isn't working. When I run <code>uname -m</code> it shows <code>arch64</code> instead of <code>x86</code>. It seems like after restarting my computer, rosetta was disabled for iterm. To reenable it all I had to do was open x86 Iterm in finder <code>cmd+i</code> and select <code>rosetta</code>.</p>
</li>
<li><p>Great we got the drone to fly using our new architecture and using some dumbed down versions of control, observation, and safety modules.</p>
</li>
<li><p>I added <code>colorama</code> as a python dependency so that I can view the logs a little easier it was really hard to see right now. I can add more tomorrow. Once I have that setup I can go through the logs with a fine comb and make sure everything is working as intended.</p>
</li>
</ul>
<h4>3/29/2026</h4>
<ul>
<li><p>Okay so I finished cleaning up the logging. Colorama does make things easier.</p>
</li>
<li><p>the <code>age_ms</code> for <code>hb_tx</code> is messed up and should something I revisit.</p>
</li>
<li><p>So it looks like we have our drone flying solely on the take off bump cause we don't ever receive any commands from the control module. The reason is because because the control module is in a <code>stale</code> state. I know this because of my logs.</p>
</li>
</ul>
<p><code>INFO [moh] control: status=stale, age_ms=4.50225, info=no_observation</code></p>
<ul>
<li>Why this is happening will probably be something I investigate tomorrow since I had a long day and I am pretty tired right now. Working on this should give me a good opportunity to learn more about observations and how versions of the control module will use it.</li>
</ul>
<p><strong>Next Steps</strong></p>
<ul>
<li><p>A day or so ago I started a conversation with ChatGPT about the logging and replay system. I want to make sure I understand it well before going down a week long project to implement it. I have to move faster now that we are getting close to April. Everyday has more weight.</p>
</li>
<li><p>If implementing this replay feature will only provide minimal returns then I will omit it completely. I may start working on other parts of the drone's autonomy stack and grow it out and the system may be implemented if needed.</p>
</li>
<li><p>I can see that there are a few modules that would deeply benefit from a system like replay. Identifying what those are ahead of time will help me decide if this is worth sinking time into.</p>
</li>
<li><p>I need to review the required modules for the first competition and hone in on working on those. That will help me answer if replay is necessary.</p>
</li>
<li><p>I need figure out at a high level how each of the modules will work and what the the pipeline will look like between them. This will help me determine the testing boundary between all of them and determine of replay works. Replay works for individual modules and stack slices to see how things improve as a whole when things get put together. It might always make sense to test a module on its own using replay and then as part of a stack slice all the way till we reach output commands. How will we keep track of improvements across stack slices and individual modules is something I need to ask chat about.</p>
</li>
<li><p>Here is the workflow that ChatGPT thinks is crucial for developing the autonomy stack.</p>
</li>
</ul>
<p><strong>Step 1: replay</strong></p>
<p>Use replay for:</p>
<ul>
<li><p>fast debugging</p>
</li>
<li><p>regression testing</p>
</li>
<li><p>module comparison</p>
</li>
<li><p>offline metric improvement</p>
</li>
</ul>
<p><strong>Step 2: live sim</strong></p>
<p>Then validate promising changes in the simulator for true closed-loop impact. That combination is what makes replay valuable.</p>
<ul>
<li>I agree this seems very valuable. Something to think about.</li>
</ul>
<h4>3/30/2026</h4>
<ul>
<li><p>Okay today is Logging and Replay investigation day.</p>
</li>
<li><p>Time to decide how we are going to implement this.</p>
</li>
<li><p>Below are two questions that I had chatgpt answer:</p>
</li>
</ul>
<p>Question 1: Can you remind me how the logging and replay is going to work? how am I to actually use the replay for testing and debugging once its working and how will I be able to use it? will it rerun a flight for a single module like its inputs and outputs? will it run all modules? Will it work with the sim? [[Logging and Replay Overview|Chats Answer]]</p>
<ul>
<li><p>The core idea is: <strong>live run → log timestamped events → replay those events later through the same topic system</strong></p>
</li>
<li><p>What gets logged: <em>Topic publish records</em> and <em>Module tick records.</em></p>
</li>
<li><p><strong>Topic publish records</strong> are the important ones. They capture data flowing through the system, like:</p>
<ul>
<li><p>IMU</p>
</li>
<li><p>attitude</p>
</li>
<li><p>local position</p>
</li>
<li><p>camera frames</p>
</li>
<li><p>detections</p>
</li>
<li><p>observations</p>
</li>
<li><p>actions</p>
</li>
<li><p>commands</p>
</li>
</ul>
</li>
<li><p>These are the records that let you reconstruct what happened.</p>
</li>
<li><p><strong>Module tick records</strong> are for introspection. They tell you:</p>
<ul>
<li><p>when a module ran</p>
</li>
<li><p>what input seq it used</p>
</li>
<li><p>how long it took</p>
</li>
<li><p>whether it was stale or okay</p>
</li>
</ul>
</li>
<li><p>These are mostly for timing/debugging, not for driving replay.</p>
</li>
<li><p>By default, replay should mainly republish <strong>source inputs</strong>, not everything.</p>
</li>
<li><p>So the main replay inputs should be:</p>
<ul>
<li><p><code>sensors.imu</code></p>
</li>
<li><p><code>sensors.attitude</code></p>
</li>
<li><p><code>sensors.local_pos</code></p>
</li>
<li><p><code>sensors.heartbeat</code></p>
</li>
<li><p><code>sensors.camera_frame</code></p>
</li>
<li><p><code>sensors.camera_info</code></p>
</li>
</ul>
</li>
<li><p>Then your current modules regenerate:</p>
<ul>
<li><p>detections</p>
</li>
<li><p>state estimates</p>
</li>
<li><p>observations</p>
</li>
<li><p>actions</p>
</li>
<li><p>safe actions</p>
</li>
<li><p>commands</p>
</li>
</ul>
</li>
<li><p>That is the most useful form of replay, because it lets you test new code on old runs.</p>
</li>
<li><p>The three main forms of replay will be [[Logging and Replay Overview#1. Whole-stack replay|Whole-stack replay]], [[Logging and Replay Overview#2. Single-module replay|Single-module replay]], and [[Logging and Replay Overview#3. Timing replay|Timing replay]].</p>
</li>
<li><p>Replay is best for debugging:</p>
<ul>
<li><p>perception bugs</p>
</li>
<li><p>estimator bugs</p>
</li>
<li><p>stale-data problems</p>
</li>
<li><p>controller behavior on the same observations</p>
</li>
<li><p>refactors that might have broken timing or dataflow</p>
</li>
</ul>
</li>
<li><p>It is much faster than rerunning the whole simulator every time</p>
</li>
</ul>
<p><strong>A concrete example</strong></p>
<ul>
<li><p>Say you do one live run and log:</p>
<ul>
<li><p>camera frames</p>
</li>
<li><p>IMU</p>
</li>
<li><p>attitude</p>
</li>
<li><p>observations</p>
</li>
<li><p>actions</p>
</li>
</ul>
</li>
<li><p>Later you improve your detector.</p>
</li>
<li><p>Now you can:</p>
<ul>
<li><p>use replay to republish the recorded frames</p>
</li>
<li><p>run the new detector</p>
</li>
<li><p>compare new detections vs old ones</p>
</li>
<li><p>optionally continue through the estimator and control modules</p>
</li>
</ul>
</li>
<li><p>That tells you whether the detector change actually improves the pipeline, using the exact same scenario.</p>
</li>
</ul>
<p>Question 2: If we are changing the code won't this affect the imu and telemetry and frames? How will this let us effectively test whether there has been an improvement? [[Replay's Limitations and Focus|Chats Answer]]</p>
<ul>
<li>Taking a look at an older conversation I had with chat [[logging and replay|here]] is what we came up with as an implementation for logging and replay. I used this older conversation as context for some ideas of what the code would look like. I think we've come up with a fair idea, tomorrow we will implement it.</li>
</ul>
<hr />
]]></content:encoded></item></channel></rss>