Speaker & L oad Cell
Speaker & L oad Cell
I am interested in learning how to wire a speaker and load cell, and use them to transfer weight to sound.
I designed a smart cup, which combines a speaker and a 5kg load cell. When the weight measured by the load cell exceeds a specific number, the speaker will play a chosen soundtrack.
Images of final creative/exploratory output
final output
Video demo
Process images from development towards creative/exploratory output
3D print base for load cell
A soldered load cell amplifier
detail images
load cell fixed on 3d printed base
A load cell amplifier and a sound amplifier fixed on breadboards
An SD card reader on breadboard
Process and reflection:
I really enjoyed this week’s domain-specific building session. Figuring out how the load cell works and designing a base for it was definitely the highlight for me—it was super satisfying to see it come together.
One thing I learned the hard way: I need to be more mindful of the hardware when I’m debugging. I ended up spending almost two hours trying to fix the code, only to realize the real issue was a loose solder connection. Lesson learned—next time, I’ll check the physical connections first before getting lost in the code.
Technical details
/*
60-223 Intro to Physical Computing, fall 2025
Domain-specific Skill Building exercise: Smart Cup
It’s a “smart coaster” that weighs what’s on it (via an HX711 load cell) and plays an MP3 sound (via a DFPlayer Mini) when the weight crosses two milestones: first at 18 g, then again at 30 g. After you remove most of the weight, it resets so it can trigger again next time.
Pin mapping:
Arduino pin | role | details
------------------------------
10+11 output DFPlayer mini
5+4 input XFW_HX711
A0 output PAM8302A
*/
code is entirely wr
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include "HX711.h"
// ---- DFPlayer on D10/D11 ----
SoftwareSerial mp3Serial(10, 11); // D10=RX, D11=TX
DFRobotDFPlayerMini mp3;
bool dfp_ok = false;
// ---- HX711 on D4/D5 ----
#define HX_DT 4
#define HX_SCK 5
HX711 scale;
// ---- Calibration ----
float CALIBRATION_FACTOR = 7050.0f; // adjust for your cell/wiring
// ---- Trigger config ----
const float WATER_TARGET_G = 18.0f; // first trigger
const float SECOND_TARGET_G = 30.0f; // second trigger
const float HYST_G = 8.0f; // re-arm below (18 - 8) = 10 g
const int TRACK = 1; // 0001.mp3
const int START_VOLUME = 14; // 0..30
bool armed18 = true; // play once when >= 18 g
bool armed30 = true; // play again when >= 30 g
void setup() {
Serial.begin(115200);
while (!Serial) { }
Serial.println(F("Boot: HX711 + DFPlayer (18g & 30g triggers)"));
mp3Serial.begin(9600);
dfp_ok = mp3.begin(mp3Serial);
if (dfp_ok) {
mp3.volume(START_VOLUME);
mp3.EQ(0);
Serial.println(F("DFPlayer online."));
} else {
Serial.println(F("DFPlayer init FAILED (check RX/TX/GND/SD /MP3/0001.mp3)."));
}
scale.begin(HX_DT, HX_SCK);
scale.set_scale(CALIBRATION_FACTOR);
delay(300);
Serial.println(F("Place EMPTY CUP on the coaster; taring in 2s..."));
delay(2000);
scale.tare(15);
Serial.println(F("Tare complete."));
}
void loop() {
float grams = scale.get_units(5);
Serial.print(F("mass[g]=")); Serial.print(grams, 1);
Serial.print(F(" 18g=")); Serial.print(armed18 ? "armed" : "done");
Serial.print(F(" 30g=")); Serial.println(armed30 ? "armed" : "done");
// First trigger: >= 18 g
if (armed18 && grams >= WATER_TARGET_G) {
Serial.println(F(">= 18 g -> PLAY ONCE"));
if (dfp_ok) mp3.play(TRACK);
armed18 = false;
}
// Second trigger: >= 30 g
if (armed30 && grams >= SECOND_TARGET_G) {
Serial.println(F(">= 30 g -> PLAY AGAIN"));
if (dfp_ok) mp3.play(TRACK);
armed30 = false;
}
// Re-arm both after weight drops well below 18 g
if (!armed18 || !armed30) {
if (grams <= (WATER_TARGET_G - HYST_G)) {
armed18 = true;
armed30 = true;
Serial.println(F("Below 10 g -> re-armed both triggers"));
}
}
if (dfp_ok && mp3.available()) { mp3.readType(); mp3.read(); }
delay(120);
}