Internet of Poop: How (and Why) I Built a Smart Litter Tray

Naturally, we want our pets to be as healthy and happy as possible, and just as with humans, one valuable metric to know is their weight. Knowing the weight of our four-legged friends, not only helps us to verify that they have a healthy amount of body fat, but can also can be used to detect things early on that may need medical attention. As they cannot speak to us and tell us when don’t feel well, it is our duty to listen to all of the different signals we have to understand their wellbeing.

Photo of a black shorthair cat sitting.

That’s why I wanted to know the weight of my cat, Ellie. Unfortunately, she really dislikes being picked up or handled, even by people she trusts. This means, it’s not possible to weigh her on a bathroom scale, and the only datapoint I have is her yearly examination at the vets. 

I wanted to build something that would fit into her life to track her weight automatically, without any intervention. I decided to modify her litter box, so that on each visit it records her weight.

But WHY, Andy?

Okay I get it; you think it’s weird. So here are the main goals of the project: 

  • Track Ellie’s weight because I want to know how heavy she is without going to the vet
  • Learn something about how load cells work
  • Have fun building a new project
  • (Hopefully) Inspire others to try out new ideas and projects by sharing what I learned. 
  • Track the weight of poops because I thought that was funny. 

The Hardware

Rather than build the whole litter tray from scratch, I decided to build a platform that her existing litter tray would rest on. This platform would contain all the equipment necessary to detect when Ellie was using the litter and start taking measurements.

I used two load cells, that I sandwiched between sheets of MDF. When a weight is applied to the top sheet, it deflects (a couple of millimetres) the load cells. The load cells came with a controller breakout board with example code, so getting up and running was really simple. As there are two cells, each one is taking a portion of the total weight (depending on where she is stood), the total weight can be found by adding them together.

Side on view of the weighting platform, showing the two load cells supporting the upper platform.

I’m not an especially talented carpenter, so it’s not the prettiest construction in the world, but you can’t see it when it’s in place, so I think that’s okay. 

Photo of the litter platform.

To take the readings, I used an ESP8266 breakout module form Adafruit. I connected this to both load cells using a reasonably long length of wire, so that I could plug in and program the litter without having to mess around with the poopy bit 💩.

Photo of me measuring wood at a workbench,

The Software

I wrote the software using the Arduino IDE. My initial plan was to create some code that: 

  1. Zeroed the current weight of the filled litter box
  2. Took a reading every second or so and waited for a jump in the weight
  3. Stored the start weight and paused for the reading to drop again
  4. Subtracted the end weight from the start weight to find out how heavy the cat is. 

As always, though, there are always things to learn that make the plan more complicated. Before the system worked reliably, it spent two weeks with it connected to a laptop, so that I could review debug data and make small modifications with each “pooping session”. It was a very frustrating process, because while I could simulate the cat by putting bottles of water on the scale, I had to wait until Ellie next pooped before I’d find out if it worked in the real world.

Upside-down Sensor???

For some reason, despite both load cells being identical, and mounted the same way around (I checked… Several times), one of them always reads upside down – that is, when a weight is applied it returns a negative value. My assumption here is that it’s a manufacturing error with the load cell and something is connected backwards internally. To resolve this, the code just inverts all readings from the dodgy cell before using them.

for (auto i = 0; i < this->SCALE_SAMPLE_COUNT; ++i)
{
    readings_a += m_scale_A.get_units();
    readings_b += m_scale_B.get_units() * -1; // 🤷🏻‍♂️
}

Sometimes (even in expensive professional products) you just need to work around hardware mistakes with the software.

Sensor Drifts

The data coming out of these sensors is far from clean, a number of things make them challenging to work with. One of those things is their tendency to slowly drift over time – usually negative, resulting in a reading of less than zero. To resolve this, I set it up so that it automatically tares both cells when not in use.

Exit and re-enter

For a while, I was getting some very confusing results from the litter tray – frequently I would get two notifications. In the first, the cat’s weight seemed plausible, but the poop weight was not, and in the seconds the poop weight seemed sensible but the cat’s was far too low.

I had a theory that Ellie may be leaving and re-entering the litter. So I set up a camera for a few hours to record what was happening. My theory was confirmed – she was leaving the litter then putting two feet inside to cover her “gift”.

To resolve this, I added the concept of a ‘litter session’ – when Ellie leaves the litter tray, it will note the end weight and duration, but will wait for an additional 60 seconds before logging it. If there is any activity in that time, it will update the data and begin waiting again.

Uncertain entry

Initially, the weight reading seemed to vary widely from one to the next. I wondered if Ellie was not entering the litter box in one clean motion but was stepping in slowly. This may cause the scale to record the start reading too low, as she still has a foot off the scale.

To handle this, the system will use the highest stable (see below) weight seen as the cat’s weight, and continually updates the start weight while it is in use.

// Update the start weight to be the heaviest stable weight we see while the
// cat is on the scale.
// This is because the cat may put their feet on the edge of the litter 
// before jumping up, so the start reading may be too low. 

if (weight > this->m_startReading) 
{
        this->m_startReading = weight;
        Serial.println("Updated cat weight");
}

What even IS stable, anyway?

When you put something in a scale, you generally put it in the weighing platform and wait for it to stop moving, to get a stable reading. But when the weight in question is a cat in their litter tray, we see a lot of movement in the load on the load cells. To handle this, the scale needs to wait until the load is “stable” – that is, it’s not moving too much. Ultimately, I elected for a relatively permissive definition of stable, where the load is within 50g of the last reading (where each reading is an average of 20 reads from both sensors).

if (abs(m_lastReading - reading) < 0.05)
{
      // Stable
}
else if (this->m_isStable)
{
    // Not stable
}

It’s important to keep in mind the scenario here, though – while this may be a bit too wide a tolerance if you were weighing flour for a cake, the cat’s weight (just like your own) can vary heavily throughout the day and each weighing session. It’s not as important to nail to exact weight to two decimal places every time, as it is to detect trends over time. 

Uses

Once Ellie has used her litter and her weight has been taken, that data is then logged via MQTT to Adafruit IO, where I can see the last 30 days of measurements on a graph to detect any trends.

Screenshot of a graph, showing the cat and poop weight over time

Once the data is in Adafruit IO, I use the Mosquitto broker to bring that data into my Home Assistant instance. This allows to me to create automations that send me a push notification so I know there’s a litter to clean, as well as to turn on the air purifier for a while to handle any smells.

Screenshot of an iOS notification saying "Ellie (3.56Kg) has left you a present in the litter box (20g)"

Source Code

The source for this project is available on my GitHub here.

Conclusions

I hope this write up was a bit of fun, and possibly educational. If you have any thoughts or feedback, I’d love to hear then in the comments, or on Twitter. If you’d like to see more of Ellie, her Instagram is here.

3 thoughts on “Internet of Poop: How (and Why) I Built a Smart Litter Tray

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.