Aquarium air pump and doser on an Arduino Uno
Two D4184 modules on pins 9 and 10 run a 12 V air pump all the time and a peristaltic pump for 3 s, 5 ml, every 20 s. The whole build, an Arduino Uno and 5 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Beginner About 20 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $38. On Mokxi they're free.
What you'll learn
- Switching a 12 V load with a MOSFET module
- Why a pin can't drive a pump directly
- Timing a pump with
millis - Turning a flow rate into a run time
- Difficulty: Beginner
- Time: About 20 minutes
- Board: Arduino Uno R3
- Parts: 6
How it works
Two pumps run on 12 V, which an Uno pin cannot supply. So each pump hangs off a D4184 MOSFET module. Pin 9 switches the air pump and pin 10 switches the dosing pump. The adapter feeds both modules, and the Uno shares their ground.
In setup the air pump goes on and stays on. In loop a timer waits DAY_MS, which is 20 seconds here so you can watch it, then starts a dose. The dosing pump runs for DOSE_MS, 3 seconds, and the sketch counts the milliliters delivered.
Parts list
6 parts, plus the jumper wires. They retail for about $38; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × DC jack and adapter
- 2 × D4184 dual MOSFET switch module
- 2 × Mini water pump
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| D4184 dual MOSFET switch module (1) pin GND | Arduino Uno R3 pin GND |
| D4184 dual MOSFET switch module (2) pin TRIG | Arduino Uno R3 pin 10 |
| D4184 dual MOSFET switch module (1) pin TRIG | Arduino Uno R3 pin 9 |
| D4184 dual MOSFET switch module (2) pin GND | Arduino Uno R3 pin GND |
| D4184 dual MOSFET switch module (1) pin VIN+ | DC jack and adapter pin V+ |
| D4184 dual MOSFET switch module (2) pin VIN+ | DC jack and adapter pin V+ |
| D4184 dual MOSFET switch module (1) pin VIN- | DC jack and adapter pin V- |
| Mini water pump (1) pin V+ | D4184 dual MOSFET switch module (1) pin OUT+ |
| Mini water pump (1) pin V- | D4184 dual MOSFET switch module (1) pin OUT- |
| D4184 dual MOSFET switch module (2) pin VIN- | Ground |
| Mini water pump (2) pin V+ | D4184 dual MOSFET switch module (2) pin OUT+ |
| Mini water pump (2) pin V- | D4184 dual MOSFET switch module (2) pin OUT- |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Aquarium pumps: a 12 V air pump that runs all the time and a 12 V
// peristaltic pump that doses 5 ml of plant food on a timer.
//
// pin 9 the air pump's D4184 module TRIG
// pin 10 the dosing pump's D4184 module TRIG
// a 12 V adapter into both modules' VIN; the Uno's GND to their GND
//
// Neither pump can run from a pin: the air pump draws about 300 mA and the
// dosing pump about 250 mA, at 12 V. A pin switches each module's MOSFETs.
//
// A peristaltic pump moves the same volume every turn, so a dose is a time.
// This one moves 100 ml a minute at 12 V, 1.67 ml a second: 5 ml is 3 s.
// Measure yours the same way (run it 60 s into a measuring cup).
//
// The real doser runs once a day; here "a day" is 20 seconds so you can
// watch it.
const int AIR = 9;
const int DOSE = 10;
const unsigned long ML_PER_MINUTE = 100;
const unsigned long DOSE_ML = 5;
const unsigned long DOSE_MS = DOSE_ML * 60000UL / ML_PER_MINUTE;
const unsigned long DAY_MS = 20000UL;
unsigned long lastDose = 0;
unsigned long doseStarted = 0;
bool dosing = false;
int doses = 0;
void startDose() {
dosing = true;
doseStarted = millis();
digitalWrite(DOSE, HIGH);
Serial.print("dosing ");
Serial.print(DOSE_ML);
Serial.println(" ml");
}
void setup() {
pinMode(AIR, OUTPUT);
pinMode(DOSE, OUTPUT);
Serial.begin(9600);
digitalWrite(AIR, HIGH);
Serial.println("air pump on");
lastDose = millis();
}
void loop() {
unsigned long now = millis();
if (!dosing && now - lastDose >= DAY_MS) {
lastDose = now;
startDose();
}
if (dosing && now - doseStarted >= DOSE_MS) {
digitalWrite(DOSE, LOW);
dosing = false;
doses++;
Serial.print("done, ");
Serial.print(doses * DOSE_ML);
Serial.println(" ml so far");
}
}
Code walkthrough
The key functions of the sketch, and what each one does.
startDose sketch.ino
Marks that a dose is running, remembers when it began with millis, and sets pin 10 HIGH to start the dosing pump. It also prints how many milliliters it is dosing. It does not stop the pump itself. That happens in loop.
void startDose() {
dosing = true;
doseStarted = millis();
digitalWrite(DOSE, HIGH);
Serial.print("dosing ");
Serial.print(DOSE_ML);
Serial.println(" ml");
}setup sketch.ino
Sets both pins as outputs and opens the serial port. Then it sets the air pump pin HIGH once, and the pump simply keeps running. Last, it records the start time in lastDose so the first dose comes one DAY_MS later.
void setup() {
pinMode(AIR, OUTPUT);
pinMode(DOSE, OUTPUT);
Serial.begin(9600);
digitalWrite(AIR, HIGH);
Serial.println("air pump on");
lastDose = millis();
}loop sketch.ino
Checks the clock every pass. If no dose is running and DAY_MS has passed, it starts one. If a dose is running and DOSE_MS has passed, it turns pin 10 LOW, adds one to the count and prints the total milliliters so far.
void loop() {
unsigned long now = millis();
if (!dosing && now - lastDose >= DAY_MS) {
lastDose = now;
startDose();
}
if (dosing && now - doseStarted >= DOSE_MS) {
digitalWrite(DOSE, LOW);
dosing = false;
doses++;
Serial.print("done, ");
Serial.print(doses * DOSE_ML);
Serial.println(" ml so far");
}
}Troubleshooting
The usual mistakes with this circuit, and the fix for each.
- The pumps do nothing This project
Check the 12 V adapter reaches both modules' VIN pins, and that the Uno's GND is joined to the modules' GND. - The dose is the wrong volume This project
Measure your pump: run it for 60 seconds into a measuring cup, then setML_PER_MINUTEto what you got. - Dosing pump runs but the air pump never does This project
The air pump is on pin 9 and the dosing pump on pin 10. Check each TRIG wire is on the right module. - Board gets too much voltage and overheats or dies. DC jack and adapter
Check the adapter voltage before plugging in. Boards like the Uno want 7 to 12 V on the jack. A 5 V part wired to a 12 V supply can be destroyed. - Nothing powers on, or the polarity is backward. DC jack and adapter
Most barrel jacks are center positive, but some are not. Check the label on the adapter, and make sure the adapter can supply enough current for the load. - The load never turns on, or it is only dim. D4184 dual MOSFET switch module
Check the load's own supply is wired to the screw terminals and the control pin gets 3.3 V or 5 V. Join the grounds of the controller and the load supply together. - Parts get hot or wires melt at high current. D4184 dual MOSFET switch module
The board can carry high current only with thick wire and good connections. Keep the load supply within the module's rated voltage, and use a flyback diode across motors and other coils. - A pump wired straight to a microcontroller pin does not run or resets the board. It draws far more than a pin can give. Mini water pump
Switch it with a logic level MOSFET or a transistor with a base resistor, from its own supply of 3 to 6 V. Join the grounds.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.