<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: k66 (Lana Chen)</title>
    <description>The latest articles on DEV Community by k66 (Lana Chen) (@k66inthesky).</description>
    <link>https://dev.to/k66inthesky</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3740921%2F8a60d690-3c1f-4432-969d-7aa64f31cda5.jpeg</url>
      <title>DEV Community: k66 (Lana Chen)</title>
      <link>https://dev.to/k66inthesky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/k66inthesky"/>
    <language>en</language>
    <item>
      <title>LLMs Have No Nose, So We Built One: an AI Nose on the Arduino UNO Q</title>
      <dc:creator>k66 (Lana Chen)</dc:creator>
      <pubDate>Sun, 18 Oct 2026 20:22:21 +0000</pubDate>
      <link>https://dev.to/k66inthesky/llms-have-no-nose-so-we-built-one-an-ai-nose-on-the-arduino-uno-q-3fhl</link>
      <guid>https://dev.to/k66inthesky/llms-have-no-nose-so-we-built-one-an-ai-nose-on-the-arduino-uno-q-3fhl</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjnn8ns1ificr5s1jnefh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjnn8ns1ificr5s1jnefh.jpg" alt="LLMs have no nose. What if we built one?" width="799" height="313"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge: Side Hustle&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;▶ &lt;strong&gt;Demo video (3:11):&lt;/strong&gt; &lt;a href="https://youtu.be/n88pRiuib3U" rel="noopener noreferrer"&gt;youtu.be/n88pRiuib3U&lt;/a&gt;&lt;br&gt;
▶ &lt;strong&gt;Code (MIT):&lt;/strong&gt; &lt;a href="https://github.com/PGASlab/app" rel="noopener noreferrer"&gt;github.com/PGASlab/app&lt;/a&gt;&lt;br&gt;
▶ &lt;strong&gt;Try it without hardware:&lt;/strong&gt; &lt;a href="https://pgaslab.github.io/pgas-sim/" rel="noopener noreferrer"&gt;live UNO Q simulation&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;
&lt;h3&gt;
  
  
  LLMs have no nose
&lt;/h3&gt;

&lt;p&gt;AI can read, write, see and listen. Ask a chatbot whether the milk in your&lt;br&gt;
fridge has gone off, though, and the honest answer is &lt;em&gt;"I can't tell, I can't&lt;br&gt;
smell it."&lt;/em&gt; Smell is the one sense we use every day to keep ourselves safe from&lt;br&gt;
bad food, and AI simply doesn't have it.&lt;/p&gt;

&lt;p&gt;So we built one.&lt;/p&gt;
&lt;h3&gt;
  
  
  Every sensor is a small nose
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq4q09qqs2zj0rpy47uvv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq4q09qqs2zj0rpy47uvv.jpg" alt="Every sensor is a small nose: MQ-135, MQ-3 and MQ-2" width="799" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A nose works because different receptors respond to different molecules. PGAS&lt;br&gt;
copies the idea with three cheap metal-oxide gas sensors, each tuned to a&lt;br&gt;
different family of spoilage gases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MQ-135&lt;/strong&gt; smells ammonia and sulfides, the "rotten egg" end of spoilage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MQ-3&lt;/strong&gt; smells ethanol, which bacteria and yeasts make as food ferments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MQ-2&lt;/strong&gt; smells a broad range of volatile organic compounds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On their own, each is just a resistor that changes with the air around it.&lt;/p&gt;
&lt;h3&gt;
  
  
  Together, they make one big nose
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqci2rpvbcrdsfal4koq6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqci2rpvbcrdsfal4koq6.jpg" alt="Together, they make one big nose" width="799" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wired to an &lt;strong&gt;Arduino UNO Q&lt;/strong&gt;, the three small noses become one. The UNO Q's&lt;br&gt;
microcontroller samples all three every second. Its Linux side compares them&lt;br&gt;
with clean air, decides whether the food is fine, and then &lt;strong&gt;acts&lt;/strong&gt;: the LED&lt;br&gt;
matrix on the board flashes a warning, an alert goes out, and your phone shows&lt;br&gt;
the verdict. No cloud, no account, no internet. It all happens on a board that&lt;br&gt;
runs from a power bank.&lt;/p&gt;

&lt;p&gt;People once tested food with a silver spoon, because silver turns black when it&lt;br&gt;
meets the sulfides of rotting food. PGAS is the modern silver spoon. We built it&lt;br&gt;
for night-market stalls and small food businesses, where selling spoiled food&lt;br&gt;
is a health risk and throwing away good food is waste.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The side hustle.&lt;/strong&gt; Many night-market stalls in Taiwan are side hustles: one&lt;br&gt;
person cooking after a day job, buying ingredients in the morning and selling&lt;br&gt;
until late. There is no food lab, only a nose and a guess about whether the&lt;br&gt;
milk for tonight's tea or yesterday's leftovers are still safe. One bad batch&lt;br&gt;
can cost a small seller their customers. PGAS is a pocket-sized second opinion&lt;br&gt;
they can carry to the stall, and it runs from the same power bank as their&lt;br&gt;
phone.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/n88pRiuib3U" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Here is one real test, photo by photo, on a bottle of milk that had gone bad.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The parts
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsomb8utlogrejyox9426.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsomb8utlogrejyox9426.jpg" alt="All parts: Arduino UNO Q, breadboard, wires, power bank and three gas sensors" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything PGAS needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arduino UNO Q&lt;/strong&gt; (bottom right): an STM32U585 microcontroller and a Qualcomm
QRB2210 running Debian Linux on one board, with a built-in 8×13 LED matrix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three gas sensors:&lt;/strong&gt; MQ-135 for ammonia and sulfides, MQ-3 (the orange one)
for ethanol, MQ-2 for broad volatile compounds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A breadboard&lt;/strong&gt; with a 10 kΩ / 20 kΩ voltage divider for each sensor, because
the UNO Q's analog pins take at most 3.3 V and the sensors output up to 5 V.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A USB-C power bank.&lt;/strong&gt; No laptop is connected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A phone&lt;/strong&gt; on the same Wi-Fi. The board itself serves the PGAS page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Control test: no food nearby
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffho1usl9xz49ct8gwy6o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffho1usl9xz49ct8gwy6o.jpg" alt="Clean-air test: " width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First we ran the full test with no food anywhere near the sensors, to make sure&lt;br&gt;
PGAS does not raise false alarms. All three sensors stayed at their clean-air&lt;br&gt;
level (rises of +0.03 V, +0.02 V and +0.00 V), and the board decided&lt;br&gt;
&lt;strong&gt;FRESH&lt;/strong&gt; in 0.6 ms. The LED matrix showed ✓.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. The suspect: a bottle of milk past its best
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqohgcq58l7b54jq3air0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqohgcq58l7b54jq3air0.jpg" alt="The spoiled milk bottle" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqf7do9qqc72vrejerqti.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqf7do9qqc72vrejerqti.jpg" alt="Milk still inside the bottle" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our test sample is a bottle of fresh milk that had been left to spoil. The&lt;br&gt;
second photo shows there really is milk inside. We poured some into a small&lt;br&gt;
container so one sensor at a time fits over it.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The guided test, one sensor at a time
&lt;/h3&gt;

&lt;p&gt;Press &lt;strong&gt;Start test&lt;/strong&gt; on the phone and the page walks you through it. Each sensor&lt;br&gt;
gets 5 seconds: 1 s in clean air, 1 s to move it over the food, 3 s measuring.&lt;br&gt;
A big countdown ring and the live reading show what is happening.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9j507rri6r7trv3hhjqp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9j507rri6r7trv3hhjqp.jpg" alt="Testing MQ-135 over the milk, countdown at 3" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MQ-135 first.&lt;/strong&gt; The sensor sits over the milk while the ring counts down.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F86y0s8sse0vzy9fz6b0v.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F86y0s8sse0vzy9fz6b0v.jpg" alt="MQ-135 and MQ-3 done, prompt to swap to MQ-2" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then MQ-3.&lt;/strong&gt; When a sensor is done, the page tells you to take it out and get&lt;br&gt;
the next one ready. Here MQ-135 and MQ-3 are ticked and MQ-2 is next.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo8x97z1jb62dwxoru69a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo8x97z1jb62dwxoru69a.jpg" alt="Pressing " width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Press the button&lt;/strong&gt; when the next sensor is in clean air. PGAS never moves on&lt;br&gt;
by itself, so you are never rushed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi6413r1eql11rq1nloik.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fi6413r1eql11rq1nloik.jpg" alt="Testing MQ-2 over the milk, countdown at 2" width="800" height="570"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MQ-2 last.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. The verdict: do not eat, do not sell
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsd8bb4sgz9lgu0err8rf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsd8bb4sgz9lgu0err8rf.jpg" alt="Result: " width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PGAS says &lt;strong&gt;Food has gone bad&lt;/strong&gt;. The MQ-3 (ethanol) rose &lt;strong&gt;+0.21 V&lt;/strong&gt; above its&lt;br&gt;
own clean-air reading, past the 0.20 V limit, so the board graded the milk&lt;br&gt;
&lt;strong&gt;DO-NOT-SELL&lt;/strong&gt; in 0.2 ms. MQ-135 rose +0.02 V and MQ-2 +0.05 V. Ethanol is what&lt;br&gt;
bacteria and yeasts produce as milk ferments, so MQ-3 is the sensor we expected&lt;br&gt;
to react most.&lt;/p&gt;

&lt;p&gt;The pop-up is written for anyone: one big verdict and one bar per sensor. It&lt;br&gt;
also lists what the agent did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sense:&lt;/strong&gt; 3 gas sensors, rise above clean air&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide:&lt;/strong&gt; DO-NOT-SELL on the UNO Q, offline, in 0.2 ms&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Act:&lt;/strong&gt; LED matrix alarm (flashing ✕), alert queued (Telegram not set up yet)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. For the curious: the live gauges
&lt;/h3&gt;

&lt;p&gt;Scroll down the same page and every sensor has a speedometer dial, its voltage,&lt;br&gt;
its normal range and a live chart. Over the limit, the card turns red and&lt;br&gt;
blinks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkkj6rl8njhy9k71f3vx4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkkj6rl8njhy9k71f3vx4.jpg" alt="MQ-3 in clean air: 0.37 V" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MQ-3 in clean air: 0.37 V&lt;/strong&gt;, inside its normal range.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3qog088hltioh6xsam6h.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3qog088hltioh6xsam6h.jpg" alt="MQ-3 over the spoiled milk: 0.70 V, card red" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MQ-3 held over the spoiled milk: 0.70 V.&lt;/strong&gt; That is almost double, and the card&lt;br&gt;
turns red.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fclisuufypy998ivwq7cb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fclisuufypy998ivwq7cb.jpg" alt="MQ-3 30 seconds after leaving the milk: 0.38 V" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;30 seconds after taking it away: 0.38 V&lt;/strong&gt;, back to its clean-air value. The&lt;br&gt;
sensor recovers quickly, so you can test the next food straight away.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MQ-3&lt;/th&gt;
&lt;th&gt;Clean air&lt;/th&gt;
&lt;th&gt;Over spoiled milk&lt;/th&gt;
&lt;th&gt;30 s later&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Module output&lt;/td&gt;
&lt;td&gt;0.37 V&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.70 V&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.38 V&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;▶ &lt;a href="https://github.com/PGASlab/app" rel="noopener noreferrer"&gt;github.com/PGASlab/app&lt;/a&gt; (MIT): the Arduino sketch, the Linux app, the phone dashboard, tests that run in CI, and a browser simulation of the UNO Q.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How it works: sense → decide → act
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sense&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MQ-135, MQ-3 and MQ-2 are read at 1 Hz with the 14-bit ADC, averaged 16×&lt;/td&gt;
&lt;td&gt;STM32U585 MCU (Arduino sketch)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Decide&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;For each sensor: rise over its own clean-air reading. An ONNX model turns the three rises into P(spoiled), checked by a safety rule&lt;/td&gt;
&lt;td&gt;QRB2210 Linux (Python, ONNX Runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Act&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LED matrix ✓ or flashing ✕, alert, verdict on the phone&lt;/td&gt;
&lt;td&gt;MCU + Linux&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The two halves of the UNO Q talk over the Arduino &lt;strong&gt;Bridge&lt;/strong&gt;: the sketch calls&lt;br&gt;
&lt;code&gt;Bridge.notify("pgas_sample", …)&lt;/code&gt; once a second, and Linux sends LED-matrix&lt;br&gt;
frames back with &lt;code&gt;Bridge.call("draw", …)&lt;/code&gt;. The phone page is served by the&lt;br&gt;
official App Lab &lt;code&gt;arduino:web_ui&lt;/code&gt; brick over Socket.IO, so the phone only needs&lt;br&gt;
to be on the same Wi-Fi or hotspot.&lt;/p&gt;

&lt;p&gt;Comparing each sensor with &lt;strong&gt;its own&lt;/strong&gt; clean-air reading taken seconds earlier&lt;br&gt;
is what makes a 5-second test work. MQ sensors drift with temperature, humidity&lt;br&gt;
and warm-up, so absolute thresholds are unreliable, but a rise within a few&lt;br&gt;
seconds is not.&lt;/p&gt;

&lt;h3&gt;
  
  
  The open-source AI: a model that runs on the board
&lt;/h3&gt;

&lt;p&gt;The verdict now comes from a small machine-learning model that runs &lt;strong&gt;on the&lt;br&gt;
UNO Q itself&lt;/strong&gt;, with no cloud:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; logistic regression in &lt;strong&gt;scikit-learn&lt;/strong&gt;, exported to &lt;strong&gt;ONNX&lt;/strong&gt; and
run by &lt;strong&gt;ONNX Runtime&lt;/strong&gt; on the board's Linux side
(&lt;a href="https://github.com/PGASlab/app/blob/main/pgas/bag_model.py" rel="noopener noreferrer"&gt;&lt;code&gt;pgas/bag_model.py&lt;/code&gt;&lt;/a&gt;).
The model file is 411 bytes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; the three rises (MQ-135, MQ-3, MQ-2). &lt;strong&gt;Output:&lt;/strong&gt; the probability
that the food is spoiled. Above 80% it is DO-NOT-SELL, between 50% and 80%
it is SPOILING.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Training data:&lt;/strong&gt; our own real measurements: the clean-air control (photo 2),
the spoiled milk in the guided test (photo 9) and an earlier spoiled-milk test.
Each one is repeated with ±0.01 V of noise, the spread we measured on a
sensor at rest.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety net:&lt;/strong&gt; three samples is a start, not a validated model. So the board
also runs the simple rule (largest rise ≥ 0.10 V SPOILING, ≥ 0.20 V
DO-NOT-SELL) and keeps whichever verdict is &lt;strong&gt;more severe&lt;/strong&gt;. A food-safety
tool should never be talked out of a warning by a model that has seen three
examples.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The verdicts in photos 2 and 9 were made by the rule; we trained the model from&lt;br&gt;
those same tests afterwards, and it gives the same answers (7% spoiled for the&lt;br&gt;
clean air, 93% for the milk). Every new labelled test makes it better:&lt;br&gt;
add the rises to &lt;code&gt;SAMPLES&lt;/code&gt; and run &lt;code&gt;python -m pgas.bag_model&lt;/code&gt;. The repo also has&lt;br&gt;
a script to optimize models for the UNO Q with Qualcomm AI Hub (&lt;code&gt;pgas/aihub.py&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Hardware
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part&lt;/th&gt;
&lt;th&gt;UNO Q pin&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MQ-135&lt;/td&gt;
&lt;td&gt;A0&lt;/td&gt;
&lt;td&gt;AO through a 10 kΩ / 20 kΩ divider (5 V → 3.33 V max at the pin)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MQ-3 (Waveshare)&lt;/td&gt;
&lt;td&gt;A1&lt;/td&gt;
&lt;td&gt;same divider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MQ-2&lt;/td&gt;
&lt;td&gt;A2&lt;/td&gt;
&lt;td&gt;same divider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heaters&lt;/td&gt;
&lt;td&gt;5 V&lt;/td&gt;
&lt;td&gt;all grounds common&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Power&lt;/td&gt;
&lt;td&gt;USB-C&lt;/td&gt;
&lt;td&gt;5 V power bank for portable use&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What we learned on real hardware
&lt;/h3&gt;

&lt;p&gt;The browser simulation got the logic right, but the real board taught us more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sketch libraries.&lt;/strong&gt; The Bridge library needs MsgPack, DebugLog, ArxContainer
and ArxTypeTraits listed in &lt;code&gt;sketch.yaml&lt;/code&gt;. We copied the exact versions from
an App Lab example on the board.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No LLM brick on our App Lab version&lt;/strong&gt;, so the advice text is rule-based.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;adb shell&lt;/code&gt; sets an Android &lt;code&gt;TMPDIR&lt;/code&gt;&lt;/strong&gt; that does not exist on the UNO Q,
which broke &lt;code&gt;arduino-app-cli&lt;/code&gt;. Our scripts reset it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensors read lower than datasheets suggest.&lt;/strong&gt; Our "sensor unplugged" check
rejected a working MQ-3, so we lowered the floor to 0.25 % of full scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan for resets.&lt;/strong&gt; During development the board sometimes rebooted, and the
app did not always come back. We never fully pinned down the cause (loose
wires on the breadboard are our best guess), so we added a keep-alive that
restarts PGAS within a minute if it is not running.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UX matters even for a sensor project.&lt;/strong&gt; Our first test took 4 minutes with a
hood over the food. One sensor at a time, 5 seconds each, guided by the
phone, it now takes about 15 seconds plus sensor swaps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;A street vendor can't depend on a subscription, a cloud API or a phone signal.&lt;br&gt;
Everything PGAS uses is open: Arduino App Lab and its bricks, the Arduino&lt;br&gt;
sketch, Python, scikit-learn and ONNX Runtime for on-board inference, and this&lt;br&gt;
code under MIT. Anyone can rebuild it for the cost of a board and three&lt;br&gt;
sensors, retrain it on their own food, or swap in a better model, and no data&lt;br&gt;
ever leaves the stall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best Use of Arduino.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It &lt;strong&gt;runs a model on the board&lt;/strong&gt;: an ONNX model decides with ONNX Runtime on
the UNO Q, offline.&lt;/li&gt;
&lt;li&gt;It is a &lt;strong&gt;physical agent that senses and acts&lt;/strong&gt;: gas sensors in, LED-matrix
alarm and alert out, with the decision made on the board in under a
millisecond.&lt;/li&gt;
&lt;li&gt;It uses what makes the UNO Q different: the MCU and Linux working together
over the Bridge, the built-in LED matrix, and App Lab bricks for the web UI.&lt;/li&gt;
&lt;li&gt;It runs &lt;strong&gt;offline on a power bank&lt;/strong&gt;, so it can work at a market stall.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;One spoiled sample and one clean-air control is a demo, not an accuracy
study. The model has seen three real samples and the rule thresholds are
provisional; both need many more foods.&lt;/li&gt;
&lt;li&gt;MQ sensors need a few minutes of warm-up and drift with temperature and
humidity.&lt;/li&gt;
&lt;li&gt;PGAS is a reference tool, not a food-safety certification. If in doubt, do
not eat it, and ask a professional.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/k66inthesky" rel="noopener noreferrer"&gt;k66&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Alitsen777" rel="noopener noreferrer"&gt;Alice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/0x29dev" rel="noopener noreferrer"&gt;29&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Crystal32378" rel="noopener noreferrer"&gt;Crystal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cynthiachi-268" rel="noopener noreferrer"&gt;Cynthia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Built with &lt;a href="https://claude.ai/code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; as AI pair programmer&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
    </item>
    <item>
      <title>🐾GitPet - No more lonely debuging</title>
      <dc:creator>k66 (Lana Chen)</dc:creator>
      <pubDate>Mon, 16 Feb 2026 07:55:57 +0000</pubDate>
      <link>https://dev.to/k66inthesky/gitpet-git-your-pet-50hp</link>
      <guid>https://dev.to/k66inthesky/gitpet-git-your-pet-50hp</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Do you ever feel lonely when you coding? GitPet is always there with you! When you &lt;code&gt;git push, git commit, git ..., etc&lt;/code&gt;, GitPet then become stronger! &lt;/p&gt;

&lt;p&gt;GitPet is a GitHub Copilot CLI extension, you can use prompt &lt;code&gt;see my GitPet status&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Repository:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/k66inthesky/GitPet" rel="noopener noreferrer"&gt;https://github.com/k66inthesky/GitPet&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;I used GitHub Copilot CLI to create this project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhnnwyn7whi601kgqizd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhnnwyn7whi601kgqizd.png" alt=" " width="800" height="293"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomu77m13x59129cisohd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fomu77m13x59129cisohd.png" alt=" " width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>🐾GitPet - No more lonely debuging</title>
      <dc:creator>k66 (Lana Chen)</dc:creator>
      <pubDate>Sun, 15 Feb 2026 17:32:31 +0000</pubDate>
      <link>https://dev.to/k66inthesky/gitpet-git-your-pet-5913</link>
      <guid>https://dev.to/k66inthesky/gitpet-git-your-pet-5913</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Feed your pet with many Git Pushes, Commits, PRs, etc!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I build
&lt;/h2&gt;

&lt;p&gt;Do you ever feel lonely when you coding? GitPet is always there with you! When you &lt;code&gt;git push, git commit, git ..., etc&lt;/code&gt;, GitPet then become stronger!&lt;/p&gt;

&lt;p&gt;GitPet is a GitHub Copilot CLI extension, you can use prompt &lt;code&gt;see my GitPet status&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Author&lt;/strong&gt;: k66&lt;br&gt;
&lt;strong&gt;Repository&lt;/strong&gt;: &lt;a href="https://github.com/k66inthesky/GitPet" rel="noopener noreferrer"&gt;https://github.com/k66inthesky/GitPet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqphe874j2ryr7x3p1hht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqphe874j2ryr7x3p1hht.png" alt=" " width="800" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

&lt;p&gt;I used GitHub Copilot CLI to create this project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5la2vg9u93w8dhm0ueg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5la2vg9u93w8dhm0ueg7.png" alt=" " width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>githubchallenge</category>
      <category>devchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
  </channel>
</rss>
