For the last couple of months, I've been using AI to develop a custom firmware for the ESP32 microcontroller family in my free time. This has been an interesting and educational experience, and I would like to share some thoughts on it.
First, I want to start by describing the idea and motive behind this project. I grew up in a Brazilian rural area, where milking is a major economic activity. One day a technician was fixing some milking equipment for my father when he complained about how expensive some PCBs replacements for milking equipment could be, then he asked me if I could develop him a compatible board for a cleaning equipment. Since the cleaning cycle was not that complex – basically opening and closing solenoid valves, heating liquids, starting and stopping motors, checking water levels, etc., and I already had developed a couple projects using the ESP microcontroller family (without any AI assistance), and, more importantly, I do like challenges, I decided to build such board.
Second, I want to give a small summary of my prior experience with AI. My first contact with LLMs was back in 2022 when GPT 3.5 was launched. Since then, I have been using LLMs mainly for quick queries using their web interface, even though I’ve already used OpenAI’s API to perform data extraction in a bibliometric dataset. Thus, I had no prior contact with tools such as Claude Code or Google Antigravity, nor I looked for “best practices” while using AI-assisted development. This means I was learning on my own.
Third, I’m developing this project using Google’s Gemini. I know there are way better models for coding, such as Claude’s models or even Grok, but since I already had a Google One subscription, I decided to use its models. Oh well, even though they may not be the leading-edge models, they are more advanced than last year’s state-of-the-art models, and, for this project, I considered they were good enough.
First thought: Get to Know AI Tools
As aforementioned, I used to use LLMs directly on their web interface. Thus, I started this project within Gemini’s web interface, a decision I regret. While web interfaces are convenient for quick queries or chats, they have many limitations when you’re building a project.
Because the web interface couldn’t interact directly with my local files, I had to constantly copy and paste code, which quickly became quite inconvenient as the project grew. The only advantage, I would say, is that I was closely reviewing the generated code while I was copying and pasting it.
Due to this limitation, I looked for ways in which LLMs could interact directly with my local files, and this is where I found Gemini-cli. Similar to Claude Code, Gemini-cli acted as a terminal-based AI agent, giving the model direct file system access to read, analyze, and modify my local project files. This meant I no longer had to copy and paste code, as the AI model was reading and editing files directly on my computer, which greatly improved my productivity.
After Google discontinued Gemini-cli, I migrated to Antigravity. As an individual AI agent, Gemini-cli interacted directly with the user through sequential execution, meaning that it executed a single task at a time, while Antigravity uses orchestration as a paradigm, meaning that it controls multiple AI agents to perform various tasks in parallel.
I admit that I’m not using Antigravity’s orchestration capabilities, which would provide a degree of autonomous development. Instead, I’m using it much like Gemini-cli, as I still want to review every change it makes to the code. Nonetheless, it remains a formidable tool.
The final lesson is this: there are many different AI tools available, each best suited for specific tasks. Getting to know and use these tools can significantly improve your productivity.
Second thought: The Risks of Autonomous AI File Editing and Context Loss
While allowing AI agents to interact with your local files and execute commands can accelerate development, it also introduces risks. AI models are not flawless. When given autonomy, they can lose context, generate bad code, break working features, or make destructive refactoring decisions.
For instance, while I was trying to fix a bug in a specific module, the AI suddenly decided to rewrite the entire thing. It was a disaster. In the blink of an eye, nearly a thousand lines of functional code were replaced by a few dozen lines of broken logic. If I hadn't maintained a recent backup, a lot of work would have been lost to the model losing its grasp of the system.
Another major risk is the AI misunderstanding strict hardware constraints. I use a memory arena to prevent heap fragmentation, which is critical in embedded systems for long-term stability. Yet, while I was simply asking the AI to help optimize the arena's size, it unexpectedly ripped out the memory arena entirely, replacing it with numerous dynamic memory allocations that would eventually crash the microcontroller.
This highlights a crucial point: catching these destructive edits requires domain knowledge. To realize the AI was making a mistake, I had to understand C++ and the specific frameworks I was using. Without that foundational knowledge to act as a filter, your project will inevitably degrade into unoptimized, fragile code, commonly referred to in the industry as "AI slop."
A quick tip: If you notice your AI is losing context, ask it to generate a session handover file and start a new conversation with a fresh context.
The takeaways are simple but crucial: strictly enforce version control (like Git) to manage backups before letting an AI touch your codebase, and rigorously review every action your AI agent takes.
Third thought: Fight Against the Path of Least Resistance
Beyond destructive file edits, another critical flaw is that AI naturally optimizes for convenience. It tends to take the path of least resistance, generating solutions that make things work as quickly as possible, often at the expense of safety, robustness, and proper architecture.
For example, I was developing a feature to keep an event on hold indefinitely until a specific release trigger fired (useful for closing a valve only after water reaches a certain level). Instead of implementing a proper, state-driven hold where the system safely waits for the trigger, the AI proposed an absurdly high delay (e.g., 9 x 10^8 ms) as a workaround. If I hadn't been paying close attention, this lazy hack would have been implemented instead of a robust solution.
This tendency is incredibly dangerous in many contexts. If asked to handle a sensor error, an AI might simply ignore the faulty reading to keep the execution loop running, rather than initiating a proper safe shutdown. If asked to build a web interface, it will likely leave it unauthenticated by default.
The human must constantly fight the AI's urge to take shortcuts by actively enforcing a paranoid, safety-first mindset. You must be the one to explicitly design the non-blocking architectures, the hardware watchdogs, and the multi-level fail-safes, because the AI will rarely prioritize them on its own.
Fourth thought: AI Can Assist, But It Cannot Truly Decide
AI can do more than just write code. It can be used in decision support by, for instance, creating comparison tables to weigh different engineering or business approaches; it can even suggest some options over others. However, both in engineering and business, the final strategic decision must be yours as, most of the time, an AI simply acts as a "yes-man" and executes your immediate instructions without stepping back to consider if the solution makes sense from a broader product or market perspective.
For example, on the first iteration of the firmware, I was looking for something straightforward. I intended to hardcode the cleaning cycle directly in C++, assuming the hardware would only ever perform this specific function. The AI happily obliged, and the code was written. However, I soon realized this approach wasn't scalable from a business standpoint. If a different milking setup required a slightly different cleaning cycle, or if we needed to incorporate unforeseen sensors, we would have to rewrite the firmware almost from scratch.
Because of this, I made the tough call to scrap code that was nearly ready for production and completely rearchitect the system.
I noticed I needed flexibility, a way to configure different cleaning cycles without recompiling C++ code. Suddenly the “replacement cleaning cycle’s PCB” became something bigger. A modular PLC like project with an event-driven architecture that is entirely configurable at runtime. With this setup, the ESP32's I/O pins can be dynamically assigned as inputs or outputs without flashing new firmware. The previously hardcoded cleaning cycles became "recipes", events what are triggered by specific sensors or buttons, with both the triggers and recipes defined in JSON files, which are human-readable and can be easily modified in a simple text editor.
I am aware this runtime flexibility introduces risks, such as accidentally configuring an output as an input and burning the microcontroller, but we implemented strict software- and hardware-based safety mitigations.
The core lesson is this: AI can help you analyze your options and write the logic, but it operates without real-world stakes. It will not independently check if the product it is helping you build is truly scalable, adaptable, or capable of satisfying your client's actual market needs.
Fifth thought: AI Only Lives in the Virtual World
Many projects involve only software. When developing a simple webpage, for example, physical hardware is hardly a concern and AI can, theoretically, hold the reins and conduct the whole process from coding to CI/CD. However, when working with embedded devices and personalized PCBs the virtual world is not enough.
To perform tests, I had to build a simplified version of the circuit using breadboards and components, an activity that, for now, AI and automation are incapable of performing (at least when building prototypes, as an industrial production can be automated).
A LLM will not be able to check if your relays were correctly activated or deactivated. Thus, even though you can ask AI to aid or review your circuit calculations, you will still be the one building it physically.
The lesson is: AI still cannot build and test things in the real physical world. This work remains yours.
Final Thoughts and Conclusions
Since GPT 3.5 was launched back in 2022, AI development has been accelerating at an exponential rate. Ten years ago, the idea of a computer program producing code autonomously with the quality of a senior engineer was nothing but science fiction, but now it is a reality. Staying updated with all the new models, tools, and paradigms, like the shift from web interfaces to autonomous agents, is challenging but essential if you want to make the most of it. However, remember that yesterday’s state-of-the-art is often good enough for today’s use. Stay updated, but don’t worry if you aren't immediately adopting every new model.
Despite how impressive today’s AI is, it still possesses critical blind spots. As I learned throughout this project, you cannot abdicate your role as the lead architect. You must strictly enforce version control to protect against destructive edits, and you must review every change to prevent the accumulation of "AI slop." More importantly, the AI will not independently verify if a solution is scalable for the market, nor will it inherently adopt the paranoid, safety-first mindset required for many real-world applications.
Ultimately, AI remains trapped in the virtual world. It can write the logic, but you are the one who must foresee electrical interference, design the physical protections, and test the circuits in reality. AI is a powerful assistant, but the strategic decisions, the hardware bridging, and the ultimate legal liability for the products you deliver rest entirely on your shoulders.
One final thought: Even though this project revolves around embedded devices, I believe these lessons can be applied to almost any AI-assisted development project. The core challenges of managing AI, such as maintaining architectural control, mitigating context loss, and avoiding lazy shortcuts, are highly transferable skills, whether you are building a physical device, a web application, or any other AI-assisted project.
As for the project, I’m currently waiting for the delivery of some parts to remove the project from a breadboard and finally build a prototype PCB. However, if you curious bellow you can see a short demo video. Stay tuned for updates.
Top comments (0)