Weight Watchdog
Obliczymy ostateczną cenę na podstawie wybranego pliku. Sprawdzisz ją i zaakceptujesz przed płatnością.
Zapisane na tym urządzeniu.
For serious tracking of your dog’s business – and a little leaderboard fun while you’re at it.
- Ocena
- 0 / 5
- Polubienia
- 11
- Pobrania
- 11
- Wydruki
- 0
- Wyświetlenia
- 1275
- Oceny
- 0
Aktualizacja u źródła:
Informacje o modelu
- Źródło
- Printables
- Kategoria
- Pets
- Licencja
- 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 screw | 12 |
| M3 x 14mm pan-head screw | 4 |
| M3 Nut | 8 |
| M3 threaded insert | 10 |
| 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 Screw | 2 |
| M4 threaded insert | 4 |
Electrical | |
| Arduino Nano | 1 |
| LCD1602 LCD display blue with I2C module | 1 |
| Gravity Digitaler HX711 Load Cell 1Kg | 1 |
| Li-Ion Akku 3.7V 3200mA NCR18650B 18650 | 1 |
| 1x18650 Lithium Batterie Shield 5V 3A / 3V 1A | 1 |
| Built-in pushbutton black 7mm 2P | 4 |
| WAGO 221-413 | 2 |
| 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 IDE | 2.3.4 was used for the development |
| PrusaSlicer | 2.9.2 was used for the development |
| Draw.io | 26.2.2 was used for the development |
| Onshape | https://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 >= 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 Height | 0.1mm |
| Infill | 20% minimum |
| Supports | Yes |
| MMU | No |
| Print Orientation | see Picture |
Grip shell | |
|---|---|
![]() | |
| Material | PLA |
| Layer Height | 0.1mm |
| Infill | 20% minimum |
| Supports | Yes |
| MMU | Text under the handle, viewing window for weighing chip LED. |
| Print Orientation | see Picture |
Weighing tongs | |
|---|---|
![]() | |
| Material | PLA |
| Layer Height | 0.1mm |
| Infill | 30% minimum |
| Supports | Sometimes, see Picture |
| MMU | No |
| Print Orientation | see Picture |
Screen panel | |
|---|---|
![]() | |
| Material | PLA |
| Layer Height | 0.1mm |
| Infill | 15% minimum |
| Supports | Yes |
| MMU | Push-button text and rings, depending on taste |
| Print Orientation | see Picture |
Adapter | |
|---|---|
![]() | |
| Material | PLA |
| Layer Height | 0.1mm |
| Infill | 15% minimum |
| Supports | Yes |
| MMU | No |
| Print Orientation | see Picture |
Weighing tongs | |
|---|---|
![]() | |
| Material | PLA |
| Layer Height | 0.1mm |
| Infill | 15% minimum |
| Supports | Yes |
| MMU | Accents and viewing window for battery charge level LED |
| Print Orientation | see 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.





