Joshua Hall
← Back

Projects.

Completed, in-progress, and future projects. Personal and academic.

01
RTL-SDRRaspberry PiLinux

ADS-B Receiver Antenna

Custom antenna designed to receive 1090 MHz ADS-B signals from aircraft, utilizing Raspberry Pi hardware to decode and display tracking data.

Apr 2025 — Present

02
RF DesignAntenna Theory4nec2

Yagi-Uda Directional 2.4GHz Wi-Fi Antennas

Pair of two highly directional WiFi antennas designed and optimized to beam a local 2.4GHz WiFi signal over long distances using ESP32 hardware and custom-built antenna booms. Simulated via 4nec2.

Apr 2026 — Present

03
LinuxStorage ArchitectureLXC Containers

Personal Server Infrastructure (Proxmox Hypervisor)

A personal cloud server hosting an expandable 6TB of mirrored cloud storage with linux containers running cloud photos, a network-wide ad-blocker, Claude Code, and remote file sharing. Accessible from anywhere via an encrypted tailnet.

Aug 2026 — Present

04
Next.jsTypeScriptVercel

Full-Stack Engineering Portfolio (Next.js, React, Keystatic CMS, Claude Code)

This website! Built using React and Next.js. Edited with Keystatic CMS and Claude Code. Launched with Vercel.

Jan 2025 — Present

05
STM32KiCadPCB Protoyping

STM32-Powered Electronic Speed Controller

Reconstructed ESC (Electronic Speed Controller) for brushless motors, designed in KiCad and prototyped on a perfboard with an STM32 Nucleo board

Dec 2025 — Present

06
ArduinoFastLEDSoldering

Audio-Reactive LED Strips

A fun project to turn my bedroom into a club using a small voltage step down module and ESP32 reading audio data from an a Focusrite audio interface to control light patterns based on frequency and amplitude data.

Apr 2026 — Present

ADS-B Receiver Antenna

Apr 2025 — Present

Custom antenna designed to receive 1090 MHz ADS-B signals from aircraft, utilizing Raspberry Pi hardware to decode and display tracking data.

RTL-SDRRaspberry PiLinuxRF DesignOptimization
See what I am currently tracking:Open live view

Overview

I consider this my signature project - one that I am certainly most proud of. During my freshman year my dorm was situated under the inbound/outbound flight path for SeaTac airport. I often used Flightradar24 to guess airplane models when they flew overhead, but I was curious if I could track them myself. No ads. No apps. My goal was to track airplanes 24/7 cost effectively and accurately.

How It Works

To start this project I researched how planes are even tracked in the first place. Flightradar24 tracks airplanes from every corner of the world… how? How does ATC manage the location of aircraft in extremely tense environments? The answer is ADS-B (Automatic Dependent Surveillance-Broadcast), a modern surveillance broadcasting system that replaces GPS. It is a highly-accurate broadcasting system that transmits aircraft location, speed, altitude, destination, type, and heading via a transponder mounted on the aircraft. These signals can be broadcast over two frequency bands, 1090 MHz and 978 MHz. My antenna is designed to read 1090 MHz, as that is the frequency most high-performance aircraft use. 978 MHz is mainly used for aircraft flying below 18,000ft.

My antenna is called a quarter-wavelength antenna, consisting of 4 ground planes and one radial sticking straight up. Each prong is a copper wire cut to 69mm, which was determined using the wavelength formula:

λ=cf=3×108 m/s1090×106 Hz=0.275 m\lambda = \frac{c}{f} = \frac{3 \times 10^8 \text{ m/s}}{1090 \times 10^6 \text{ Hz}} = 0.275 \text{ m}
λ4=0.0688 m69 mm\frac{\lambda}{4} = 0.0688 \text{ m} \approx 69 \text{ mm}

To account for conduction losses in the wires due to thickness and soldering connections, wavelength is multiplied by 0.95 to get around 65mm. I didn’t think of this at the time of initial construction, so all of my radials are around 69mm. The antenna still performs great compared to other antennas I researched online. I will go more into performance optimization later, as some other fascinating changes drastically improved my performance.

Current performance as of August 2026 (visit here). This data is new as the antenna has been offline due to me moving:

My antenna ‘core’ is an SO239 Female FR Coax connector, which screws on to the end of a coax cable and provides mounting holes on the four corners with a vertical element. These pieces are used for a wide variety of different antenna applications. This component provided an easy base that allowed me to connect a coax cable straight to my antenna. Next, via a 20ft RG8x coax cable, my data is then sent into an ADSBexchange RTL2832U 1090MHz filter. ‘Filter’ is the key word here, as this component is a bandpass filter that ensures any noisy frequencies from cell phones, TV’s, and FM radio don’t interfere with the data that my Raspberry Pi reads. Being in the University District, signal interference is a big deal. The RTL2832U is just a blue stick that plugs in via USB-A into my Pi and has a small coax male end. I used an adapter to connect my RG8x coax to the stick. I researched that these filters are basically required since they boost signal quality by so much. They were listed in almost every tutorial I researched. They are usually very expensive, so I ordered a cheaper one on amazon that doesn’t exist anymore and it seems to do the job. Last but not least, the brains of my operation, a Raspberry Pi 4B. This project was my first time using Raspberry Pi, and I had a blast setting it up and discovering what these little computers are capable of. Luckily for me, ADS-B antennas have a large community with plenty of open source software on github that makes setup (mostly) straightforward.

My data is acquired through the filter via USB and is first run through readsb, a popular decoding software. This turns whatever data that is passed through my filter into actual aircraft data that is readable. The output of this program can be a wicked-fast list of latitudes, longitudes, model numbers and speeds updating every second, but I wanted to visually see my tracked planes on a map, just like Flightradar24. At this point, my data junctions in two directions within my Pi. A program called tar1090 reads my readsb data and outputs my aircraft data on map with a convenient list of all aircraft currently tracked by my antenna, the number of aircraft currently tracked, and a messages/sec statistic that I used to test the performance of my antenna. The readsb data is also sent to a Flightradar24 program that allows hobbyists like me to send my tracking information to their app and enhance their tracking models, with a free business-tiered subscription as a reward. I discovered that I could do this during my software setup phase on the Pi, so it motivated me even more to enhance my data. At this point, I had a fully working antenna setup that read a specific frequency, decoded aircraft signals, and displayed them on a map that I could see in my dorm room 24/7.

For fun, I bought an old Dell XPS from 2015 off of a guy on facebook marketplace, gently tore out the screen, and used its LCD display as the main screen for my Pi so I could have a live map continually running in my dorm room for me and my roommate.

A large portion of this project was optimizing my setup to get the best possible messages/sec. This statistic was congruent with data quality, number of aircraft tracked, and range. More messages meant more planes and smoother updates. When I first got the software set up, I used a stock antenna that was shipped with my filter, and got around 15 msg/sec, which was quite low. This roughly translates to about 15 aircraft with ~20 miles of range. I plugged in my DIY antenna and that immediately jumped the messages to 60-80 with over 40 aircraft tracked simultaneously. This was because the stock antenna was just a vertical radial, it had no reflectors (the four ground planes on my antenna) that allowed better directionality. After lots of software research, physical positioning changes, and deeper research into what interferes with ADS-B signals, I discovered the following parameters that I adjusted to get optimal tracking quality.

    Physical space around the antenna was the single most important factor in data quality. This surprised me initially and I discovered this by accident. When I first plugged in my antenna, it was free to move around and only bound by the long coax cable, so the first thing I did was move the antenna right next to my window, and I discovered that the proximity to a solid surface decreased the quality of my data. If I held the antenna in the center of my dorm room away from walls, I acquired better data. When I returned home for the summer, I built a mount out of PVC pipes to put the antenna on the roof of my house. Since the antenna was out in open air with a clear view of the sky, I was able to track planes all the way south to Portland, OR, and north to Vancouver, BC. This was where I acquired my best data: 258 messages/sec with over 150 nautical miles of range.Within readsb there is a digital gain parameter that boosts or quiets incoming ADS-B signals into my antenna. My understanding of the parameter is like this: my antenna is like a microphone and nearby aircraft are emitting a sound (not engine noise, but their ADS-B data) at a certain volume. If the aircraft is further away, its sound is quieter. If it's closer, it's louder. The digital gain parameter is essentially turning up the sensitivity of my ‘microphone’ which records the ADS-B ‘sounds’. The higher the gain, the louder distant signals are, but so are closer signals. If my gain was too high, nearby aircraft would blast my antenna with huge amounts of noise, causing my messages/sec to skyrocket and clip the data coming in, causing the data to be unreliable and sometimes unreadable. I attenuated my gain so I could get more range without clipping nearby signals.Geographical location is the last optimization that had a large impact on my performance. This parameter, however, was the hardest to change because where I lived greatly impacted the performance of my antenna. In the dorms, I had a fantastic view south with minimal obstructions, so I was able to reach Oregon from my dorm. But since I was at the south edge of the building, I wasn't able to track much further than 10 miles north of my dorm. At home, which is 45 minutes southeast of Seattle, gave me the best performance because of the open air. Both of these locations had Mt. Rainier impact tracking performance, as tar1090 showed my range would drop out just around the mountain due to its size. Long story short - clear, open, flat views provided the best performance.

Result

I’ve learned a lot from working on this project and iterating on it over time. I discovered the general workings of how antennas work, aircraft communication, how to use Raspberry Pi hardware and software, and most importantly: troubleshooting. Throughout the entire course of the project I was constantly researching and using AI to find solutions to bad data or malfunctioning software on my Pi. The project was a lot of trial and error, most of it was brute forcing though software setups and not understanding how they worked, but over time I learned how to dissect where my errors originated more efficiently. Lastly, I acquired a free business tier subscription for sending my tracking data to FlightRadar24 which unlocks a plethora of tracking features. I also discovered a lot about aircraft routes in the area (SeaTac flips which directions planes land and takeoff based on weather and time of day), busiest airspace times (about 4pm), and when certain aircraft fly over my location every day.

Updates

20 August 2026

Migrated ADS-B decoding to run on my Proxmox server. Configured a tracking map to a tailnet tunnel to allow live internet access to my tracking. Re-established graphs1090 to collect tracking data and performance. Started a daily JSON file backup of tracking data stored on the server to allow future LLM learning capabilities on my tracking data. Read more on the server process here.

25 Jul 2026

Antenna offline for 2 months. Establishing a new location to mount the antenna indoors and establish connection with Flightradar24 and begin collecting Graphs1090 data.

Yagi-Uda Directional 2.4GHz Wi-Fi Antennas

Apr 2026 — Present

Pair of two highly directional WiFi antennas designed and optimized to beam a local 2.4GHz WiFi signal over long distances using ESP32 hardware and custom-built antenna booms. Simulated via 4nec2.

RF DesignAntenna Theory4nec2ESP32Optimization

Overview

The goal of this project is to create a hardware 'hotspot' that can provide an extension of our apartment WiFi network to a location that is out of range of a router. The idea for this project stemmed from an issue related to my ADS-B antenna, which was to create a wireless option to send data over our network instead of using a cellular communication method.

My Role

I teamed up with one of my roommates, Ben Stebbins, an aerospace engineer at the University of Washington and CAD Lead for the Steel Bridge team, to design the physical structure of the pair of antennas. Together, we both navigated through simulating and optimizing the raw antenna design using 4nec2. My role is building the antenna hardware, which consists of soldering coax between the driving element to the ESP32, assisting in the director design, powering the antennas, programming the ESP32's as wifi repeaters and access points via esp-wifi-repeater, and optimizing data transfer speeds through physical testing.

How It Works

As my second antenna project, it is important to note that I have not taken an antenna theory course during my time at UW. Despite this, I have been able to learn enough about antenna theory (and just general antenna construction knowledge) to be able to build yet another pair of copper wire antennas. There are two identically antennas in this project, acting as senders and receivers. They are essentially two wireless bridges. Both antennas will have an ESP32 acting as the computers receiving and sending WiFi data. The bulk of the work required to construct this antenna is through simulations, which allowed us to try a multitude of antenna configurations to acquire a gain high enough to perform well in terms of dBi while also ensuring we did not pass any legal limits (the FCC does not limit dbi, but the power that you broadcast with). Our is 14.22 dBi, and the physical gain limit of an antenna of our size is 15. If we wanted to increase our gain past 15, the length of our boom and number of elements would have to double just to increase by a few dBi. At our simulated gain, we discovered that this would be plenty, as store bought versions of these antennas reached over a few miles with line-of-sight. Since our goal was to go a few hundred feet, we considered this more than enough. And, the higher the gain, the narrower our antennas would project our signal.

Our antenna, as seen in the 4nec2 simulation photos above, consist of 12 copper wires: 1 driver, 1 reflector, and 10 directors. The driver, the second to last wire, is what turns our copper wires into a functioning antenna. This driven element is soldered to a coax cable that is then connected to the ESP32, which converts current into electromagnetic waves. This is an extremely similar setup to my ADS-B antenna, which has a Raspberry Pi → coax → antenna. By itself, the driver would be useless without the reflectors and drivers. To our understanding, more directors = higher gain. They can be thought of as lenses for our driven signal, magnifying and focusing to a specific point. The last and widest copper wire is a reflector which acts as a mirror for any of the signal moving backwards, redirecting it forward and providing extra gain. The driver is cut close to half wavelength to efficiently convert current data to electromagnetic waves, the directors are then cut shorter to pull the waves forward across the antenna in the direction we want to go. The reflector is cut longer than half wavelength to act as a wall, opposite to the directors. it forces the signal away from the back of the antenna and rather pushes it "down the hill" of the directors. 4nec2 helped us figure out how long our copper wire would need to be, how spaced apart they should be along the boom, and the thickness of the wire. All of this data was collected in a table, but as we finished our boom design we had to adjust the length of our wires.

#ElementPosition from driven (mm)Old length (mm)New length (mm)Radius (mm)
1Reflector-25.006050.60.5
2Driver05646.5
3Director24.995443.9
4Director50.045343.3
5Director87.435343.8
6Director112.605343.4
7Director150.225242.7
8Director187.065242.4
9Director225.115242.2
10Director263.135241.9
11Director299.095141.7
12Director337.865141.6

Our PLA prototype boom design has PLA covering part of the wires. Through the help of Claude, we learned that when waves traveled through the PLA, the copper wires acted longer than they actually are physically.

Dielectric Constant of PLA1.75\text{Dielectric Constant of PLA} \approx 1.75
Boom Width=30 mm\text{Boom Width} = 30\text{ mm}
Excess Length=30(1.751)=9.686 mm\text{Excess Length} = 30(\sqrt{1.75} - 1) = 9.686\text{ mm}

We had to reduce the width of our wires to account for this change so our gain calculation would account for this phenomenon.

The plan:

    3D print our antenna booms. Ben designed the boom with a latching mechanism as the length of the boom is slightly too big for most printers. This allows the boom to be printed in two separate spaces, allowing for versatile printing environments.
    Setup the ESP32's as repeaters. This step is the most interesting for me, as we need to allow the hardware to send WiFi via our custom antennas. An important note, the ESP32's need a 32UE chip, which has a fancy u.FL (SMA) pigtail connector to allow us to attach a coax cable between the chip and the driving element. Antenna #1 will have an ESP32 mounted on the back, powered via a wall adapter (this unit will be mostly stationary as it will be the exit point from our home network). This unit will be in STA (station) mode, which allows it to connect to our WiFi network like any other device via the ESP32 built-in antenna. It will also be running in AP (access point) mode, creating a new network that will be broadcasted over the Yagi that has its own unique name and password. This is the bridge network between the two ESP32's. Unit 2 will also be set up in AP mode, but this time it will receive (and send) the signal over the antennas and then broadcast its own network (YagiLink), which is an extension of our home network. Through this entire process, each ESP32 will be using NAT, network address translation, (enabled via firmware) which shuttles the data between networks all the way back to our router. Without NAT, these networks would be isolated and wouldn't allow data transfer over the antennas. At this point you may be wondering, how fast will this internet be? The limits of these antennas aren't the Yagi's themselves, but rather the small built-in antennas on the ESP32's. These antennas are what will be connecting to our router on one end, and then broadcasting a new network on the other end. Since ESP32's are meant to be microcontrollers and not routers, the max speed of the antennas is ~150mbs. But since these antennas are both sending and receiving data, and doing this twice (send and receive for the device/router, send and receive over the antenna bridge), best case we get speeds around 30mbs, which is optimistic. We expect speeds around 15mbs, which is enough to send a text, look something up (don't try loading this website), and most importantly, send aircraft tracking data - my original problem. All firmware will be flashed via Arduino IDE.

Result

To be updated!

Updates

08/06/2026

Our first printed prototype of our antennas is officially in-hand! The print was generally successful, with a minor fix that did not require a re-print after visual inspection. The print was split into two pieces, a bow and stern, which took ~100 minutes to complete, respectively. They fit together very snug (with the help of a mallet), but provide an impressively rigid structure. The holes for the director wires looked dangerously small for a 1mm wire upon first glance, so I used a 1/16in (1.54mm) drill bit to widen the holes for some extra wiggle room. The second antenna was printed by one of my mechanical engineering co-worker at Panasonic this week and will be in-hand next week. Our next step will be mounting the ESP32's on the back, installing the copper wire directors, driver, and reflector. Once all of the components fit on our design, and we confirm that the coax routes successfully through the stern, we will

07/25/2026

Finished preliminary boom design. Printing confirmed for week of Jul 27

Personal Server Infrastructure (Proxmox Hypervisor)

Aug 2026 — Present

A personal cloud server hosting an expandable 6TB of mirrored cloud storage with linux containers running cloud photos, a network-wide ad-blocker, Claude Code, and remote file sharing. Accessible from anywhere via an encrypted tailnet.

LinuxStorage ArchitectureLXC ContainersNAS

Overview

The genesis of this project is recent, but for an extended period I have always wanted to build a personal NAS (Network Attached Storage) server, partly because my father is upset that I have used up all of my family iCloud storage. A NAS is very similar to cloud storage, which is a location off-device with a large pool of storage where you can pay to have your files, photos, movies, or anything else you may think of, stored in the cloud. A NAS is exactly like these cloud storage systems, but instead of being in a datacenter within a big company, you build, configure, and maintain the system yourself - on a smaller scale. The only downsides are upfront costs and the need for maintenance, but that is a price I am more than willing to pay. All of the software I run to store photos, mitigate ads, and enable remote access is free and open-source, allowing me to securely and cheaply manage a cloud system. This project has helped me learn about operating Linux systems (especially through the terminal), how to allocate computer resources to specific containers, and build a robust system that is accessible from anywhere with secure connections. This project is consistently in-progress, so check back to see new updates to kronor!

How It Works

Hardware Specifications:

RAM32GB DDR4
CPUIntel i5 1400K
GraphicsIntel Integrated Graphics
Power750W

Storage

125 GB 2.5in SATA

500 GB NVMe SSD

2x 6TB 3.5in NAS Hard Drives

I bought the hardware for this project with a few criteria in mind. 1) Low cost, 2) low noise, 3) versatility/upgradability. My Fractal Meshify 2 case has modular components that can be configured to be in a server layout. This sacrifices space you would normally save for a GPU for a large stack of drive bays instead. The server runs completely headless, which means that it is never connected to a computer monitor, keyboard, or mouse. All of my interactions with the machine happen via my wired network (or Tailscale if I am out of the apartment). I knew this going into the build, so I bought a chip with integrated graphics to ensure I could log in if needed, or if I decided to rebuilt the system from a software standpoint. This also saved me a ton of money as graphics cards are abysmal to purchase due to RAM, hence the older DDR4 I purchased for this build. My motherboard has extra slots, so if I need more RAM I have the space. I settled with DDR4 because most of the tasks I would be running would not be bandwidth intensive rather than raw GB. Since my OS is incredibly light weight, and I have a moderate i5 CPU, I can run the stock cooler and use the case fans. So far, my CPU runs at a crisp 36-degrees celsius.

My server runs an operating system called Proxmox, which is a Linux-based server management software that allows you to launch containers (CT) and virtual machines (VM) on the base kernel of the machine. On a larger-scale server, this sort of OS is extremely useful as you can containerize different processes into their own separate "zones" that are completely isolated from one another. I mentioned earlier that the system runs headless, so all of my work conveniently happens on my MacBook Pro in a typical workflow like this:

In the window on the left, I can use the shell of my server (kronor) which is launched for the web environment on the right. From here, using commands, I can enter into each of my unique containers. Each container has a specific number of allocated CPU cores from my chip that it is allowed to use, along with a certain amount of ram. Unlike the RAM, which is specifically reserved for each container, cores can be shared among processes if there is free resources.

Now, why is having containerized processes significant? Firstly, each container is truly a completely isolated system. The apps installed in each container are installed on the NVMe, but each container can point to and use any external connections (like my NAS drives). If a process in one container crashes, breaks, corrupts… or I cause a little oopsy, the drive can essentially be wiped and then re-established with zero effect to anything else running on the server. Additionally, each container gets assigned its own IP address, which means that even my internet sees every container running on my server as a separate "device". This is incredibly useful when accessing my server via Tailscale (an encrypted network (tailnet) that links all devices on the network together). I can use my Mac and remote into each container and make meaningful changes, while having the security of knowing that no other processes are being effected on the server.

For example, I have a container named "cloudDrive". This container establishes pools (essentially folders) on my large 6TB drives. I then installed Samba, an open-source software that allows me to send and receive files to the respective storage pools using a special SMB protocol. I then have another container that has access to my antenna. This container is configured with software that can decode the ADS-B signals and then stores them to a specific location on my drives. The ADS-B container has no knowledge of the storage pools (other than a pointer to a hole to the drives so it knows it can send files there), likewise the cloudDrive. Any data that gets read and written by either container doesn't affect the other. Additionally, the software itself on each container is stored on the NVMe, so if an issue arises I can reinstall the software or wipe the container and still have all the stored data intact.

Running Processes

101 (cloudDrive)

Container 101 currently runs Samba, which allows Linux machines share files over a network (my tailnet, read about Tailscale below). This network links all of my chosen machines together. Samba is the language that lets me drag and drop files directly in my Finder on Mac to my server. This container is configured with a bind mount which lets the container see files in a specific folder on the drives. This folder is called kloud (spelled with a k for kronor), which is a massive pool to store any type of files that I want from my Mac. The purpose of this is be able to store most of my documents on this drive to maximize portable space on my Mac (1 TB). cloudDrive is the host for my kloud folder, thus I can make more folders on the drive. These folders are isolated, however, because the folders are created on different containers. This keeps things convenient because I can log onto the cloud drive as a different user, (like logging into a different container within Proxmox) and manipulate/store files in these folders without affecting the other containers.

102 (adsb)In-progress..
TailscaleIn-progress..

Result

Placeholder

Full-Stack Engineering Portfolio (Next.js, React, Keystatic CMS, Claude Code)

Jan 2025 — Present

This website! Built using React and Next.js. Edited with Keystatic CMS and Claude Code. Launched with Vercel.

Next.jsTypeScriptVercelVSCodeClaude Code

Overview

It was indeed not my first choice to host a website with GoDaddy or Squarespace due to some personal wallet limitations… and the ancient Wordpress environment provided by UW did not fit my design fancy. After meeting with a Sonos software engineering manager, he suggested Vercel, a free hosting service to push your own product - free for personal use. The only caveat: you must build the website yourself. My Java skills wouldn't cut it for how ambitious I wanted to be with this website, but thanks to AI, I was able to turn my mental ideas into something tangible. This website is completely vibecoded. Design changes, page additions, all of the guts and internals were built using Claude. Whenever I had a new idea, I referred to Claude, who turned my ideas into code within my portfolio working directory. This project doesn't necessarily highlight my coding skills, but rather my fluency in navigating a software development and the creative ideas we can deploy with AI . Building this website has been an absolute blast because I can show off my designs, spend my time writing about my experiences, and instantly launch updates instead of paying hundreds of dollars a year on a hosting service or learning advanced JavaScript. I have spent my time learning how patch security flaws on the web, how to navigate large projects using bash, deploying AI agents to work on different aspects of my website, and learning the piplenline from my project folder all the way to the internet. Additionally, I have learned how to be concise with AI, how to give it context for issues, steer it on the design path I envision, and build something in a time frame that wouldn't be humanly possible a few years ago. Let me reassure you, everything you have read has been written by me. My goal with this website, along with displaying my engineering journey, is to show that I do not let AI speak for me on this website, but rather assist me as a tool and as a companion within my engineering problems to learn about the topics that genuinely interest me and hand off the redundant tasks.

How It Works

The entire structure of my website is contained to a project folder that I edit in VSCode and the terminal, which consists mainly of TypeScript and JSON files. Any edits made to the website happen in this project folder. The entire structure is also stored in a Github repository which Vercel linked to and repeatedly checks for new deployments. Vercel then takes the repository and launches the website to the web, hosted on their servers. Any edits that I make to the project are not seen by Vercel until I manually push the updates to GitHub, which is a convent way of developing the website without effecting the live site. The domain for the website, jswhall.com, is purchased through Vercel for $12.00 a year, the rest of what I am building the website with (besides Claude) is free. The website is built using React, which is a javascript library that builds user interfaces. On top of react, my website uses Next.js which adds additional functionality to react, such as quicker load times, interactive components, and enables more load processing to be done within the browser rather than as server. When I am developing the site, I go between Claude when I want to make a design change, and a Keystatic local developer server running directly on my machine to add text like you're reading now. I can also open a local version of the website in my browser that updates as I make changes, which allows me to see exactly how the site will look before it goes live on the web. The Keystatic environment is a way for me to edit all of the text and content on the website without having to edit JSON and .txt files within the code. The only aspect of this project that I pay for is for my domain, the rest is free.

Result

This development system, powered by Claude, is incredibly seamless for such a versatile work environment. I will be able to make future edits infinitely since the project lives on my personal machine. I have created an environment that is expandable, cheap, and essentially limitless in terms of creativity because Claude code is my software developer. And with the Keystatic editing environment, I have a clutter-free place to write about my projects and experience. I get asked how I host the site and how much it costs and people are often surprised that I have been able to launch something this customizable with the help of AI. Anyone can do this, so feel free to reach out with any questions!

STM32-Powered Electronic Speed Controller

Dec 2025 — Present

Reconstructed ESC (Electronic Speed Controller) for brushless motors, designed in KiCad and prototyped on a perfboard with an STM32 Nucleo board

STM32KiCadPCB ProtoypingSoldering

Overview

The most ambitious of my engineering endeavors, this project originated as a task for my WAAR (Washington Aerial Robotics) club. I was tasked with redesigning a 4-in-1 ESC (Electronic Speed Controller) with the purpose of merging it on the same board as a 5A buck converter. WAAR’s goal is to build fully autonomous drones that are less than 1lb, so the purpose of merging the buck and ESC is to minimize complexity and weight. As I stated initially, a full ESC redesign was much more complex than I or any of my club leadership expected, so the scale of this project has turned into something more R&D for a singular ESC to control one motor. That way, when one prototype works, we can essentially ‘copy paste’ the design 3 more times. The direction of the club, for the summer 2026 competition at least, has shifted towards a premade ESC, with the goal of using my ESC work next year.

How It Works

An electronic speed control works to control brushless motors, not to be confused with brushed motors. Unlike brushed motors, brushless require alternating currents through 3 separate phases to drive 3 coils that induce a magnetic field to pull a spinning motor. The physics behind the motor are complex and not the goal of what I am trying to convey here. The critical information to know is there is a PWM switching frequency that controls how fast the MOSFET’s turn on and off on an ESC. This controls how much average voltage reaches the BLDC motor. There is also an Electrical Commutation Frequency, which is defined by the motor's speed. This is how fast the phases alternate to drive the motor speed. I already discussed the nature of how a brushless motor is driven here in my WAAR Notion folder, if you are unfamiliar with BLDC motors. Any questions you may have after reading my work here will most likely be answered in this file:

https://www.notion.so/Electronics-Speed-Controller-3256b287dfd480c699cecdc5e1bcf5b4?source=copy_link

NOTE: What has been completed for this project is a KiCad schematic and a full soldered prototype on a perfboard*. I am currently working with my firmware lead to upload code to an STM32 Nucleo dev board to power and control the prototype ESC at the time of writing this (05/15/2026). This will be a major milestone in the development of this ESC. If it does not function properly it will require a lot of debugging.*

I began this project with zero knowledge of how an ESC functioned – which led to a lot of research. Not so long after I began this research I realized how difficult it is to properly design an ESC due to the extremely rapid power modulation that occurs within the circuit. Subtle changes in capacitor locations could introduce fluctuations in the PWM current that could cause the phases to not output their correct voltage. I decided to start simple, which led me to find a schematic created by someone making a simpler ESC design for one motor with an Arduino as the driving hardware. The schematic was relatively simple, the only difference being the computer for the ESC – which is a big difference. I reached out to a former club member of WAAR who currently works at SpaceX and he suggested to use an STM32 Nucleo developer kit, which is essentially another kind of Raspberry Pi or Arduino, but instead mimics the properties of the actual STM32 chip we are planning to use on the finished product. In a simplified manner, I was replacing the Arduino in the schematic I found with the Nucleo as it has all of the same functionality needed to generate PWM signals, read phase currents, and run open-source motor control software. Once I had hope that the schematic could be driven by the Nucleo, we ordered the parts to design a larger working prototype. I decided with my leadership to develop a working prototype from the schematic before designing the PCB to ensure that our design functioned properly without fully committing to the bit. This part of the project took the longest. It took almost a month to get all of the right parts. Once I acquired everything I spent a week building the prototype. All components on the board are the exact components that would be on the PCB other than the MOSFETs. The MOSFETs on the prototype have all the same specifications other than they have a much higher voltage rating, hence their large size. Continuity was tested on all nodes, so theoretically everything is wired correctly.

I have concerns over the performance of the ESC that could cause us to run into issues:

    The quality of the wiring used is subpar. Any increase in resistance of excess wire length can introduce back-emf or unreliable currents that could drive the motor incorrectlyAt the time of writing this I have no knowledge of C++, but hopefully the open source software should suffice for our testing. I am unsure of the ease of simply plug-and-playing software with hardware it has never seen. I truly do not know the outcome but I will update as the project continues.

Result

The results of this project are fairly unknown and still in-progress, but I can discuss what stands so far. I have a decent looking prototype board with quality solder connections. This was one of my most intricate soldering jobs, and after finishing the soldering all connections were tested for continuity, all of which passed. I also learned about MOSFET’s and how they are used in HI and LOW sides to drive different directions of current. Lastly, I have been getting into the trenches of how STM-based hardware can be tested using their Nucleo dev kits. From setting up the IDE’s to wiring the dev board to my esc are all tasks I am learning and problem solving through as I progress. The further I make it through, the more excited I am to see if my prototype works. Stay tuned!

Audio-Reactive LED Strips

Apr 2026 — Present

A fun project to turn my bedroom into a club using a small voltage step down module and ESP32 reading audio data from an a Focusrite audio interface to control light patterns based on frequency and amplitude data.

ArduinoFastLEDSolderingAudio ProcessingESP32

Overview

Write-up in progress...

How It Works

Write-up in progress...

Result

Placeholder

Lab Final Projects — Academic Coursework

EE 201

Autonomous Line-Following Robot

Dec 2025

An autonomous robot that follows a line using a custom photoresistor PCB sensor array and a PID control loop programmed via Arduino IDE. Built as a group final project.

ArduinoPID ControlPCB DesignSoldering3D Printing
EE 233

Tri-Band Audio Filter

Mar 2026

A multi-band active audio filter designed using op-amps and passive components, applying Laplace transform analysis for low-pass, band-pass, and high-pass filter stages.

Filter DesignOp-AmpsCircuit TheoryLaplace Transforms
EE 331

AC/DC Converter & Booster

Jun 2026

An AC to DC rectifier circuit with a boost converter stage, designed and tested as a final lab project applying semiconductor device theory.

Power ElectronicsRectifierBoost ConverterSemiconductors