Skip to main content

Command Palette

Search for a command to run...

Training and Deploying a Custom Bird Detector on the Google Coral Dev Board Micro

From Shawn Hymel’s Object Detection Tutorial to My Own TinyML Bird Detector

Updated
11 min read
Training and Deploying a Custom Bird Detector on the Google Coral Dev Board Micro
K

I’m an IoT firmware/software engineer who loves bringing ideas to life by designing, building, and maintaining IoT solutions from the ground up. My expertise spans everything from hardware design to full-scale deployment, ensuring every step is seamless and efficient. I’m passionate about robotics and mechatronics engineering, and I have strong skills in ROS and other essential tools. As a full-stack IoT developer, I enjoy tackling complex problems and creating innovative, reliable solutions that make a real impact.

Why I Started This Project

I have been exploring TinyML and edge AI because I am interested in how machine learning can move from notebooks and cloud servers into real physical devices.

It is easy to train a model in Colab and celebrate the accuracy numbers. But the real question for me was different:

Can I take a model I trained myself and make it run on an actual embedded board with a camera?

That was the goal of this project.

I wanted to train a simple bird detection model, compile it for the Edge TPU, deploy it on the Google Coral Dev Board Micro, and see the board detect a bird through its own camera.

The target class was simple: "bird"

Not bird species classification. Not a large wildlife monitoring system yet. Just one class. If a bird is in the frame, detect it and draw a box around it.

The bigger goal was to understand the full pipeline from collecting the data to deploying the model on the device and debugging.

What is TinyML?

TinyML is machine learning on small, low-power embedded devices.

Instead of sending data to the cloud every time you want to make a decision, the device can run a small model locally. That means the device can sense, process, and respond without always needing internet connectivity.

For example, a TinyML device can listen for a keyword, classify motion from a sensor, detect a person in a camera frame, or identify something happening in the environment. For me, this is important because many practical systems in agriculture, robotics, environmental monitoring, and remote sensing cannot always depend on fast internet or cloud processing.

A farm sensor, a drone payload, a wildlife monitoring camera, or a field device should not always need to upload everything before making a simple decision.
That is why TinyML matters.

  • It brings intelligence closer to where the data is collected.

For beginners, I recommend this book:

TinyML: Machine Learning with TensorFlow Lite on Arduino and Ultra-Low-Power Microcontrollers by Pete Warden and Daniel Situnayake

Why the Google Coral Dev Board Micro?

The Google Coral Dev Board Micro was interesting to me because it is not just a normal microcontroller board.

It has a camera, a microcontroller-style development environment, and access to an Edge TPU accelerator. That makes it a nice platform for experimenting with embedded computer vision.

The board allows you to test ideas like:

  • object detection

  • image classification

  • tiny smart camera systems

  • wildlife monitoring

  • farm monitoring

  • robot vision

  • environmental sensing

For this project, I wanted to use it as a small smart camera.

The idea was simple:

The board sees an image, runs the model locally, and returns the detection results.

That connects directly to TinyML because the intelligence is happening on the device, not somewhere far away in the cloud.

The Coral Dev Board Micro also has a practical development flow where you can access the board through a browser and view camera output. That made it suitable for my experiment.

The Starting Point Was Shawn Hymel’s Tutorial

I did not start from zero.

The foundation for this project was Shawn Hymel’s DigiKey tutorial on custom object detection with the Google Coral Dev Board Micro.

That tutorial showed the path for setting up the Coral Micro SDK, building firmware, flashing the board, serving camera frames, and viewing object detection results in the browser.

That was the perfect starting point.

But I did not want to only repeat the tutorial. I wanted to use the structure Shawn had already created and push it further with my own trained model. The original flow uses a model file and firmware logic built around the expected output format. In that workflow, metadata.hpp plays an important role in helping decode the model outputs.

My project eventually moved away from that.

But at the beginning, my thinking was simple:
Let me follow Shawn’s example first, get it working, then replace the model with my own.
That sounded simple. It was not.

The Pain Point , When Things Started Breaking

his was the frustrating part.

I tried to follow the same example and get the original setup working, but a lot of things were not smooth.

Some tools and dependencies had changed. Some parts of the older workflow were no longer behaving the way I expected. MediaPipe-related parts and parts of the model preparation flow were giving issues. I was trying to reproduce the example, but the environment was fighting back.

At one point, it felt like every step opened another problem.

The model conversion was not straightforward.
The firmware expected one thing.
The model output gave another thing.
The browser was not always showing what the serial output suggested.

And sometimes the board appeared to be running, but I could not tell if it was using the model I thought I had uploaded. This is where the project stopped being a simple tutorial and became a real debugging exercise.

The lesson was clear:

In embedded AI, the model is only one part of the system.

What We Did Differently

Instead of depending fully on the original training path, we developed our own training workflow.

We still used an SSD-style object detection model, specifically:

SSD MobileNet V2 FPNLite 320x320

The model was trained as a one-class detector:

bird

The dataset came from Kaggle:

CUB-200 Bird Species XML Detection Dataset

Even though the dataset contains many bird species, we collapsed the classes into one label: bird.

That made sense for this first experiment because I was not trying to classify the exact species. I only wanted the board to detect whether a bird was present.

The training workflow prepared the dataset, trained the model, exported it, converted it to TensorFlow Lite, and compiled it for the Edge TPU.

The final model file was:

model_int8_edgetpu.tflite

That is the model the firmware loads on the Coral Dev Board Micro.

After that, we updated the firmware to match the output of our new model.

That was the key step.

The Big Firmware Change, Removing metadata.hpp

One of the biggest changes we made was removing the old metadata.hpp dependency.

The original firmware flow expected metadata.hpp because the model output needed metadata and anchor decoding.

But our trained model included detection post-processing.

That means the model was already returning final detection-style outputs.

So instead of manually decoding anchors, the firmware could read the outputs directly.

The output mapping we confirmed was:

output 0 = scores
output 1 = boxes
output 2 = num_detections
output 3 = classes

The bounding box format was:

[ymin, xmin, ymax, xmax]

with values normalized between 0.0 and 1.0.

That changed the firmware logic.

Instead of saying:

use metadata.hpp to decode anchors

the firmware now says:

read scores
read boxes
read number of detections
read classes
apply threshold
send JSON to browser

This made the firmware cleaner for this model.

It also made the pipeline easier to understand.

The Threshold Issue, Why It Detects at 0.33

This is important to explain clearly.

The current model is working, but it was trained for testing, not final production accuracy.

Training for many steps takes longer. Since this was a first working experiment, we trained with fewer steps and used a lower threshold to confirm that the model could run and detect something on the board.

The current firmware threshold is:

static constexpr float score_threshold = 0.30f;

So if the board shows a score like:

0.33

the firmware accepts it because:

0.33 is greater than 0.30

That is why the browser can show detections around 0.33.

This does not mean 0.33 is the final standard. It means the model is working and the threshold is currently low for testing.

The threshold is configurable.

If someone trains the model for more steps, improves the dataset, or gets stronger confidence scores, they can increase the threshold:

static constexpr float score_threshold = 0.50f;

or:

static constexpr float score_threshold = 0.70f;

For this stage, the lower threshold helped prove that the custom model and firmware pipeline were working.

Use your browser screenshot where the detection score is around 0.33. Add a caption like:

The model detects the bird at about 0.33 because the test threshold is currently set to 0.30.

The Browser Display Problem

Another issue was the browser display.

The firmware was producing detection JSON. The serial monitor showed that detections existed. But at one point, the browser was not drawing the bounding boxes properly.

That told us the model was not the only issue.

The display layer also mattered.

The solution was to follow a Shawn-style canvas approach:

fetch image from /camera_stream
fetch detection JSON from /bboxes
draw image on canvas
draw boxes on the same canvas

Drawing the image and boxes on the same canvas helped avoid alignment issues.

The board now serves:

/camera_stream
/bboxes

and the browser page handles the display.

We also moved the webpage into a separate index.html file instead of embedding everything inside the firmware.

That makes the project cleaner because the firmware handles camera and inference, while the HTML handles display.

It Works, But It Is Slow

The model works.

The firmware runs.

The browser can show detections.

But the current firmware is still slow.

Some of the serial logs showed timing values in seconds. That means the current system is not yet optimized for smooth real-time detection.

This is not surprising. The board is doing several things:

capturing camera frames
copying image data
running inference
compressing JPEG
serving images over USB HTTP
serving JSON
updating the browser
printing debug logs

All of these affect speed.

There are a few ways to improve this later. One option is to optimize the firmware so inference happens faster.

Another option is to change the workflow so the board captures a still image, runs inference, and returns the result, instead of trying to behave like a continuous video detection system. For some applications, that is enough.

For example, a field camera does not always need 30 FPS. It may only need to wake up, capture an image, detect whether something is present, and send an alert. So the current version is not the final speed-optimized version. It is a working proof of concept.

What I Would Improve Next

The current model works, but there is room to improve it.

The next improvements would be:

1.train for more steps
2.add more negative/background images
3.improve the bounding box annotations
4.test with real camera images from the Coral Micro
5.increase the threshold after better training
6.reduce false positives
7.profile the firmware timing
8.separate camera capture time from inference time
9.reduce JPEG overhead
10.test still-image inference mode

The model sometimes gives loose boxes, including full-frame detections. That is likely more of a model and dataset issue than a firmware issue.

Better data and longer training should improve that.

The firmware can also be optimized later.

For now, the important thing is this: the custom model runs on the board
That is the milestone.

Credits

This project builds on the work of Shawn Hymel.

His Coral Dev Board Micro custom object detection tutorial gave me the foundation for this experiment. I strongly recommend starting with his DigiKey tutorial and video before trying this project.

Credit also goes to the Google Coral team for the Coral Dev Board Micro, the Coral Micro SDK, and the Edge TPU ecosystem.

This work is my own adaptation and extension of that foundation. My contribution was to train a new custom bird detection model, update the firmware for the model’s output format, remove the metadata.hpp dependency, adjust the threshold for testing, and document the full process.

Resources

All proper documentation to train your custom Object Detection model for TinyMl is here on my github repo