1 / 11
Weight Watchdog — image 1
1 / 11

Weight Watchdog

Order a print of this model

We calculate the final price from your selected file. You review and accept it before payment.

Saved on this device.

For serious tracking of your dog’s business – and a little leaderboard fun while you’re at it.

Rating
0 / 5
Likes
11
Downloads
11
Makes
0
Views
1,275
Reviews
0

Updated at source:

Model information

Category
Pets
License
Creative Commons — Attribution — Noncommercial — Share Alike

Essential Tracking. Unexpected Fun. Welcome to Weight Watchdog.

The Weight Watchdog is a practical yet playful device designed to monitor your dog's poop weight. Inspired by morning walks past Robidog stations, it started as a creative twist on pet care – and grew into a tool that can genuinely support canine health.
Tracking waste consistency over time can reveal early signs of medical issues and help pet owners stay informed about their furry companions.

The design features a rugged, portable handle, a crisp LCD display, and an intuitive button interface. Live weight readings, a high score list, and the ability to name your four-legged champion – it’s all built in.

Whether you're a vigilant pet owner, a veterinary enthusiast, or just appreciate clever gadgets – Weight Watchdog has you covered.

 

Functions

  • Weighing dog waste bags with load cell
  • Loadcell up to 1kg, with up to 2kg possible
  • Three highscore places with the option of entering corresponding dog names
  • Powered by Arduino Nano
  • Recharchable Battery
  • LCD Screen
  • Simple operation via 4 buttons
  • Attachment tunnel for more bags or a carrying sling
  • Data stored in the eprom
  • Battery charge level indicator with LED
  • LED shows the status of the load cell
  • Easy to change weighing adapters

 

 

 

Hardware and Software Used

Mechanical

Name
Quantity
M3 x 6mm pan-head screw 6
M3 x 12mm pan-head screw12
M3 x 14mm pan-head screw4
M3 Nut8
M3 threaded insert10
  
M4 x 11mm screw (Any head, just not a hexagon)2
M4 x 19mm screw (Any head, just not a hexagon)2
M4 x 20mm Allen Screw2
M4 threaded insert4

Electrical

Arduino Nano1
LCD1602 LCD display blue with I2C module1
Gravity Digitaler HX711 Load Cell 1Kg1
Li-Ion Akku 3.7V 3200mA NCR18650B 186501
1x18650 Lithium Batterie Shield 5V 3A / 3V 1A1
Built-in pushbutton black 7mm 2P4
WAGO 221-4132
Various strands of wire 
Solder 

Tools

3D printer with minimum 200mmx200mm buildplate
Soldering iron
Knife for cleaning edges
Allen key set
Side cutter
Wire stripper
Flashlight or headlamp

Software

Name
Version
Arduino IDE2.3.4 was used for the development
PrusaSlicer 2.9.2 was used for the development
Draw.io26.2.2 was used for the development
Onshapehttps://www.onshape.com/

 

Wiring Diagram

 

Code

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%WeightWachtdog%%%%%%%%%%%%%%%%%%%%%%%%%%%//
//Spring 2025
//https://www.printables.com/@BGDglider_2502284

//######################################################################// //######################################################################// ///////////////////////////////////INIT/////////////////////////////////// //######################################################################// //######################################################################//

/****************************** Libraries *******************************/ #include <Wire.h> #include <LiquidCrystal_I2C.h> #include <HX711.h> #include <EEPROM.h>

/****************************** LCD Setup *******************************/ /*Here you have to set the Adress of your I2C LCD Screen, you can *******/ /*find out the Adress by using a I2C Scanner ***************************/ /*Adresses look like 0x27 or 0x3F ***************************************/

LiquidCrystal_I2C lcd(0x27, 16, 2);

/****************************** HX711 Setup *****************************/ HX711 scale; float calibration_factor = 1100.0;

/***************************** Taster Pins ******************************/ const int buttonLeftPin = 2; //Left const int buttonMidPin = 3; //Set Reset const int buttonRightPin = 4; //Right

/*********************************** Pages ******************************/ int currentPage = 0; // 0 = Live, 1–3 = Highscores, 4 = Help

/************************** Highscores und Names ************************/ float highscores[3] = {0.0, 0.0, 0.0}; char names[3][9] = {"---", "---", "---"};

/************************** Debounce & Reset ****************************/ unsigned long lastButtonTime = 0; const unsigned long debounceDelay = 200; unsigned long buttonMidPressTime = 0; const unsigned long longPressTime = 10000;

/************************** Char dekl. **********************************/ const char charSet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ "; const int charSetLength = sizeof(charSet) - 1;

//######################################################################// //######################################################################// ///////////////////////////////////SETUP////////////////////////////////// //######################################################################// //######################################################################//

void setup() { /************************* LCD and Splashscreen *************************/ Serial.begin(9600); lcd.begin(); lcd.setBacklight(HIGH); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Weight Watchdog"); lcd.setCursor(0, 1); lcd.print(" Initializing..."); delay(2000);

/************************* Initialize Scale *****************************/ scale.begin(A2, A3); scale.set_scale(calibration_factor); scale.tare();

/************************* Initialize button ****************************/ pinMode(buttonLeftPin, INPUT_PULLUP); pinMode(buttonMidPin, INPUT_PULLUP); pinMode(buttonRightPin, INPUT_PULLUP);

/************************* Initialize Highscores ************************/ loadHighscores(); updatePage(); }

//######################################################################// //######################################################################// ///////////////////////////////////LOOP/////////////////////////////////// //######################################################################// //######################################################################//

void loop() { handleButtons();

if (currentPage == 0) { float weight = scale.get_units(10); lcd.setCursor(0, 1); lcd.print("Weight: "); lcd.print(weight, 1); lcd.print(" g "); }

delay(100); }

/************************* Buttonhandling *******************************/ void handleButtons() { if (millis() - lastButtonTime < debounceDelay) return;

if (digitalRead(buttonLeftPin) == LOW) { currentPage = (currentPage - 1 + 5) % 5; updatePage(); lastButtonTime = millis(); }

if (digitalRead(buttonRightPin) == LOW) { currentPage = (currentPage + 1) % 5; updatePage(); lastButtonTime = millis(); }

if (digitalRead(buttonMidPin) == LOW) { buttonMidPressTime = millis(); while (digitalRead(buttonMidPin) == LOW) { if (millis() - buttonMidPressTime >= longPressTime) { resetHighscores(); updatePage(); return; } }

float measured = scale.get_units(10);
int position = checkHighscore(measured);
if (position &gt;= 0) {
  enterName(position);
}
updatePage();
lastButtonTime = millis();

} }

/************************* Pagehandling *********************************/ void updatePage() { lcd.clear(); switch (currentPage) { case 0: lcd.setCursor(0, 0); lcd.print("Current"); break; case 1: case 2: case 3: lcd.setCursor(0, 0); lcd.print("Highscore #"); lcd.print(currentPage); lcd.setCursor(0, 1); lcd.print(names[currentPage - 1]); lcd.print(": "); lcd.print(highscores[currentPage - 1], 1); lcd.print("g"); break; case 4: lcd.setCursor(0, 0); lcd.print("1s - SetScore"); lcd.setCursor(0, 1); lcd.print("10s - ResetScore"); break; } }

/************************* Highscore ************************************/ int checkHighscore(float value) { if (value > highscores[0]) { highscores[2] = highscores[1]; strcpy(names[2], names[1]); highscores[1] = highscores[0]; strcpy(names[1], names[0]); highscores[0] = value; return 0; } else if (value > highscores[1]) { highscores[2] = highscores[1]; strcpy(names[2], names[1]); highscores[1] = value; return 1; } else if (value > highscores[2]) { highscores[2] = value; return 2; } return -1; }

/************************* Namehandling *********************************/ void enterName(int index) { char tempName[9] = " "; int pos = 0; int charIndex = 0;

while (pos < 8) { lcd.clear(); lcd.setCursor(0, 0); lcd.print("Name ("); lcd.print(pos + 1); lcd.print("/8):"); lcd.setCursor(0, 1); for (int i = 0; i < 8; i++) { if (i == pos) lcd.print('_'); else lcd.print(tempName[i]); }

bool confirmed = false;
while (!confirmed) {
  if (digitalRead(buttonLeftPin) == LOW) {
    charIndex = (charIndex - 1 + charSetLength) % charSetLength;
    delay(200);
  }
  if (digitalRead(buttonRightPin) == LOW) {
    charIndex = (charIndex + 1) % charSetLength;
    delay(200);
  }
  if (digitalRead(buttonMidPin) == LOW) {
    tempName[pos] = charSet[charIndex];
    confirmed = true;
    delay(300);
  }

  lcd.setCursor(pos, 1);
  lcd.print(charSet[charIndex]);
}

pos++;
charIndex = 0;

}

strncpy(names[index], tempName, 8); names[index][8] = '\0'; saveHighscores(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Saved!"); delay(1000); }

/************************* Resethandling ********************************/ void resetHighscores() { for (int i = 0; i < 3; i++) { highscores[i] = 0.0; strcpy(names[i], "---"); } saveHighscores(); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Highscores reset!"); delay(2000); }

/************************* Savehandling *********************************/ void saveHighscores() { for (int i = 0; i < 3; i++) { EEPROM.put(i * 10, highscores[i]); for (int j = 0; j < 8; j++) { EEPROM.update(30 + i * 8 + j, names[i][j]); } } }

/************************* Loadhandling *********************************/ void loadHighscores() { for (int i = 0; i < 3; i++) { EEPROM.get(i * 10, highscores[i]); for (int j = 0; j < 8; j++) { names[i][j] = EEPROM.read(30 + i * 8 + j); } names[i][8] = '\0'; } }

I2C Scanner Code

To find out the I2C Adress of your LCD Screen, you can run this Code:

#include <Wire.h>

void setup() { Serial.begin(9600); Wire.begin(); Serial.println("\nI2C Scanner"); }

void loop() { byte error, address; int nDevices;

Serial.println("Scanning..."); nDevices = 0; for (address = 1; address < 127; address++) { Wire.beginTransmission(address); error = Wire.endTransmission(); if (error == 0) { Serial.print("I2C device found at address 0x"); if (address < 16) { Serial.print("0"); } Serial.print(address, HEX); Serial.println(" !"); nDevices++; } } if (nDevices == 0) { Serial.println("No I2C devices found"); } else { Serial.println("done"); } delay(5000); }

 

Printing Instructions

Handle core

Material  PLA
Layer Height0.1mm
Infill20% minimum
SupportsYes
MMUNo
Print Orientationsee Picture

Grip shell

Material  PLA
Layer Height0.1mm
Infill20% minimum
SupportsYes
MMUText under the handle, viewing window for weighing chip LED.
Print Orientationsee Picture

Weighing tongs

Material  PLA
Layer Height0.1mm
Infill30% minimum
SupportsSometimes, see Picture
MMUNo
Print Orientationsee Picture

Screen panel

Material  PLA
Layer Height0.1mm
Infill15% minimum
SupportsYes
MMUPush-button text and rings, depending on taste
Print Orientationsee Picture

Adapter

Material  PLA
Layer Height0.1mm
Infill15% minimum
SupportsYes
MMUNo
Print Orientationsee Picture

Weighing tongs

Material  PLA
Layer Height0.1mm
Infill15% minimum
SupportsYes
MMUAccents and viewing window for battery charge level LED
Print Orientationsee Picture

 

Assembly Instructions

Handle

Starting with the handle core, solder two M3 threaded inserts into the side holes and two M4 threaded inserts into the top and bottom two holes.

Place the digital weight sensor in the side recess and fasten it with two to four M3x14 screws and M3 nuts.

Insert the two plugs into the digital weight sensor and connect the load cell. Then guide the cables into the cable cut-outs provided.

Guide the load cell through the grip shell.

Guide the handle shell over the handle core, taking care not to pinch any wires.

Once the grip shell has been slipped over the grip core up to the limit, it can be fastened with the side threads and two M3x6 pan-head screws.

The load cell can now be screwed to the bottom of the handle core with two M4x19 screws. Be careful not to pinch any wires.

Now the handle is ready for marriage with the adapter.

Attach the weighing tongs to the load cell using two M4x11 screws.

Screen panel

The four pushbuttons can be screwed into the four holes in the screen panel using the spring washers and nuts supplied. Pay attention to the alignment of the nuts for the look and the contacts on the back to make the connection easy.

The LCD can be inserted into the recess and screwed on with four M3x12 pan-head screws and four nuts.

Rear view

Electrical work

Now it is time to wire and solder the parts. This allows definitive tests to be carried out before the components are installed.

Attention, don't make the same mistake as I did and wait to connect the load cell to the Arduino Nano. It is sufficient to wire the battery unit, screen panel and Arduino.

Preparing the adapter

The adapter has cut-outs for the Wagos and the Arduino. Two M4x20 Allen screws are used to connect the adapter to the handle.

Preparing the housing

Eight M3 threaded inserts are embedded in the housing.

The first four will later be used to attach the adapter.

The other four are used to attach the battery shield. It is best to lay the housing on its side, work with plenty of light and lift the threaded insert directly on the soldering iron to the hole to melt it in (sorry for the hidden position).

Adapter - handle

The adapter can now be screwed to the handle. Pull the wires through the correct opening and do not pinch anything.

Assembling the remaining parts

Again, take your time with the soldering. I was again hasty and connected the load cell too early.

Mount the battery shield in the round cut-outs, paying attention to the orientation. The small round recess is to provide access to the USB C port. The four M3x6 pan head screws required are best lifted into the mounting holes with needle nose pliers and then tightened with the allen key.

The load cell cables can now finally be fed through the lower opening and connected. The patience has paid off.

Now the Screen panel can be mounted on the front. Use M3x12 pan-head screws for this. These are screwed into the plastic.

The adapter has cut-outs for the Wagos and the Nano. I have not used these, but this would certainly be the cleaner option.

The weight watchdog can now be closed with four M3x12 pan-head screws. To do this, screw the housing onto the adapter.

 

Demo and Usage Instructions

 

Turn on Weight Watchdog

To switch the Weight Watchdog on, press the On/Off button once. 

During initialization, the Weight Watchdog should be kept straight and steady to avoid poor initialization.

You can then scroll through the menu via >>> or <<<.

 
Weighing and setting a high score

The currently measured weight can be read on the weighing page. If a bag with contents is now hooked onto the hook, the weight of the bag can be measured. The weight is read in by pressing the set button. If the weight is greater than the three saved high scores, the new high score is saved. The dog name can now be set on the input screen. Use >>> and <<< to scroll between the letters and select with the set button. It is possible to enter a dog name with up to 8 characters.

 

View highscore

On the three highscore pages, the three highest measured weight values can be viewed with the corresponding dog names.

 

Helppage

The help page explains that to reset the high score, the set button must be pressed for more than 10 seconds.

 

Turn off Weight Watchdog

To switch off the Weight Watchdog, the On/Off button must be pressed twice in quick succession.

 

Tags