Built-in project · Arduino Uno R3

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.

The circuit runs here once the page has loaded.

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.

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 pinConnects to
D4184 dual MOSFET switch module (1) pin GNDArduino Uno R3 pin GND
D4184 dual MOSFET switch module (2) pin TRIGArduino Uno R3 pin 10
D4184 dual MOSFET switch module (1) pin TRIGArduino Uno R3 pin 9
D4184 dual MOSFET switch module (2) pin GNDArduino 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.

sketch.ino · Arduino Uno R3
// 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 set ML_PER_MINUTE to 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.