I2C works great on a breadboard demo and then starts failing once real cable lengths and motor noise show up. I now treat I2C reliability as a physical-layer problem first and a software problem second.

My baseline checklist is simple: short wires, a shared ground reference, and one clear pull-up strategy. Mixed breakout boards often stack pull-ups in parallel, which can make rise times too fast and stress devices. I remove extra pull-ups and measure SDA and SCL with a logic analyzer before changing code.

On the firmware side, I always add retry logic around each sensor read and detect repeated NACK patterns. If retries exceed a threshold, I reinitialize the bus and record the event to serial logs. That gives me field data instead of guessing.

The biggest improvement came from separating high-current loads from sensor routing. Moving motor wires away from the I2C harness and adding a local decoupling capacitor near the sensor cluster reduced random timeouts almost completely.