Feedback-Driven 12V PWM Controller

Balance Is The Key

Rob Bell & Mike Hansell

Issue 12, June 2018

This article includes additional downloadable resources.
Please log in to access.

Log in

Most pulse width modulation (PWM) controllers simply allow you to create a reliable PWM output, perhaps with a soft start feature. This fantastic project takes control to an entirely new level.

With so many PWM controllers, we’re specifically setting a desired duty cycle that we want. This might give us a slower speed motor, a dimming function on a lamp, or some other function. This is great for those tasks where the actual result doesn’t need to be precise. But what if you don’t care about the duty cycle itself, just the result?

Not quite following? We'll break it down for you.

Standard PWM Setup :

This flow chart shows how an ordinary PWM controller would be used to set the duty cycle. You adjust the duty cycle to get approximately the current (which translates to motor speed etc), and leave it.

fig 1

Feedback Driven PWM Setup :

fig 2

This version uses feedback from a sensor, to dictate the PWM instead. You set the target range, and the software adjusts the hardware accordingly, to meet those demands.

Let’s look at practical-use cases where this would be appropriate.

Heating or Cooling

You need to generate a certain amount of heat through an electric heating element. You don’t care what the actual duty cycle required is, you just want a specific temperature. This is somewhat how a soldering station with adjustable temperature will work. You don’t set a PWM level, you set a target temperature. By utilising a temperature sensor, the heater element can work at a level suitable to maintain temperature, regardless of the environmental influence.

Oil Pump

Oil changes viscosity (the thickness, internal friction, or consistency a liquid has) based on its temperature. As a result, warmer oil is easier to pump than cool oil because it flows more freely. Think of it like butter in a frying pan. Butter from the fridge is solid, but at cooking temperatures it’s entirely liquid. For this reason, if you set your oil pump to run at a particular speed using a traditional controller, and the temperature of the oil gets cooler, you may find the oil isn’t getting where it’s required.

Water Pump

Many of us in Australia have water tanks and pumps, for various purposes. The feedback mechanism can be used to compensate for variable “head height”. That is, the vertical height the water has to travel to get from the pump to the end of the hose. If you raise the end of the hose by 1m, it’s going to take a lot more energy to pump the water at the same rate. This may be just an inconvenience if you’re watering the garden with lower pressure, but if you need to guarantee flow, the feedback loop will adjust the pump to achieve constant flow.

Air Blowers

The output being measured doesn’t have to be a flow. Perhaps you have an engine room or generator in a shed, which requires constant ventilation to ensure exhaust gases don’t become toxic. You could monitor air quality and automatically adjust air blowers to run when exhaust gases are detected, running faster when concentrations are higher.

Really, the uses are virtually endless. The only conditions required to put this into practice are:

  1. A measurable “output” (by way of sensor or internal metering).
  2. A PWM controllable load to adjust the output.
  3. Both pieces of hardware are capable of producing, and monitoring at the level you want (i.e., a water pump which can adequately produce desired flow, and a water flow meter that can monitor the flow).


In some of our examples, a simple thermostat might seem like a good solution. However a thermostat only has two states: on or off. This system uses the feedback loop to modify the duty cycle through the entire range, so you have on, off, and everything in between (okay, around 250 odd steps between, but you get the idea).

When other factors change (viscosity, outside temperature, head height), the controller will make the pump work harder or softer, to achieve the target you have set. The result is a more analogue output (ironic being PWM, we know) from the hardware being controlled, than what a thermostat can provide.

Of course, it’s limited to 0% and 100% duty cycle. So your pump, blower, or whatever you’re controlling must actually be capable of the range you require, and be adequately rated for the task. We still can’t make a pump run faster than it can work from full power. If we figure that out, we’ll let you know!

The major improvement here, is that the system is constantly auto-correcting. Regardless of outside variables, you’ll always achieve the output you’re chasing, as long as it’s within the technical capabilities of the hardware you’re using.

This auto-correction mechanism could theoretically also be expanded to provide redundancy in critical systems. Instead of running one pump, run two pumps at half-capacity. If one fails, the other can take up the slack. Everything would automatically be adjusted to maintain the flow rate required. Though we’re getting a little ahead of ourselves.


First, let us explain what we mean by “the result”. When we make the decision to spin a 10,000RPM motor using a 50% duty cycle PWM output, the motor won’t necessarily spin at 5,000RPM. If you run a 100 Lumen LED from a 20% duty cycle PWM output, you probably won’t see an output of precisely 20 Lumens.

In some applications, this is totally irrelevant. In many instances, simply reducing the motor speed to “slower” or reducing the light output to “not as bright”, is a perfectly acceptable outcome. The wheel will turn slower, the lighting will be softer, or whatever the case may be. But what if you do indeed have specific requirements where you’re more concerned with the output itself, than the PWM duty cycle used to get there. Or what if you do want your motor to turn 100 revolutions per minute, or your pump to run at precisely 10 litres per hour? It’s cases like these, where our feedback-driven PWM controller provides stability and control over the output, rather than setting an arbitrary PWM value that seems good at the time.


We have explained the basics of PWM and duty cycle previously, but here’s a quick recap.

Many DC-powered devices can be made to run slower or faster, or glow less or more brightly by changing the amount of current flowing through them; these devices include LEDs, motors, fans, pumps, and many more. Note that we’re only dealing with DC motors/fans/pumps here. Due to the complexity, safety, and legal problems involved with mains power, all instances refer to 12V or lower DC-powered devices.

A simple way to achieve this variation in current flow is by using pulse width modulation (PWM). Most microcontrollers including Arduino and Raspberry Pi can generate a “square” (or more importantly a “rectangular”) waveform from their digital pins. A square wave implies equal positive (high going) side and a negative (low going) side of the waveform. A rectangular wave implies that the positive side may not be same width as the negative side. The positive side can be thought of as the “on” side. The other side is off. If we had an LED connected, we’d see that its relative brightness would be half that of a direct (with current limiting resistor) connection across a power source. If we could vary the width of the positive side of the waveform, we would vary the amount of energy fed to the load (LED, motor, etc). If we made the positive side wider, more energy would be fed to the load. A narrower positive side would give less energy to the load. This is in fact, pulse width modulation.

fig 7
Standard DC current, which is constant and does not fluctuate.
fig 8
A low duty cycle current (approximately 10%) shows full voltage for a very short period, then no voltage for a long period.
fig 9
A high duty cycle current (approximately 90%) shows full voltage for a long period, then no voltage for a very short period.
fig 3

The overall frequency of the duty cycle does have some consequences on the circuit being controlled, however for our purposes we'll disregard frequency selection as the overall operation of our project is unaffected by the frequency.


If you have used a standard PWM controller such as our “Choppy PWM Controller” circuit, you’ll be very familiar with the act of turning the potentiometer one way or another to increase or decrease the duty cycle, based on what you want. Turn the dial up, things speed up/get brighter; turn the dial down, they slow down/get dimmer. This is the most basic, linear, non-feedback mechanism of PWM control, and works rather brilliantly when that’s all you need.

This is where our feedback loop comes in. It is effectively a digital hand on the dial, to adjust things up and down as required. Of course, there’s no actual potentiometer involved (though a stepper motor connected to a potentiometer could theoretically provide similar functionality).

The critical component for success here is the measured output via the feedback sensor, and the target set by the touch screen. It simply compares the detected rate of flow (or whatever you’re measuring) with the target rate. It then makes a decision to increase or decrease the PWM level (or make no change if it’s already producing the target output). This way PWM is the method we used to achieve the target, not the thing we’re controlling directly.


There are all sorts of sensors that can be used. The awesome thing about this project is that it doesn’t matter what type sensor you use. It simply needs to be something that’s proportional to the load you’re driving.


There are many devices, such as fans, which have an internal sensor output in the load itself, that you can easily use. Tachometer outputs from fans, pumps, and other rotating devices are often available to provide an indication of running speed.

At its most basic form, this project will allow you to maintain a constant speed for a fan, pump, or other load.

It’s probably worth noting that a simple air fan such as in a computer, doesn’t have a whole lot of variation. To some degree, a clogged-up filter will impair the fan due to restriction of the incoming air. The system will ensure the fan speed is maintained as much as possible, up until the point of 100% duty cycle (full power).

integrated sensor


Perhaps the most practical configuration is to use an output sensor. For a water pump, that would be a flow sensor. For a fan, it would be an anemometer. We’re directly monitoring the desired outcome from the load we’re controlling.

It means you can ensure that liquid flows consistently at all temperatures and mixtures, air flow is maintained even with filters that are clogging up (the fans are made to work harder), and other scenarios that are likely coming to your mind.

This will often be more useful than an integrated sensor, because you’re measuring the actual result of the action the load is performing. Perhaps the water pipes are sludged up, you are ensured water still flows at the measurement point, for instance.

fig 6


While an output sensor covers many different applications, there’s also scenarios where you don’t care about the direct action (such as the water movement); instead the metric of successful operation is dictated by a separate factor entirely. Let’s say you have a water pump and radiator to keep water cool in a piece of machinery; you don’t really care how fast the water is moving or the speed of the fan as it spins, you only care about the temperature of the cooling water itself.

Let’s also note here that by “unrelated”, we mean it’s basically a result of a secondary effect of the load you're controlling rather than a direct one. By all accounts, an output sensor is directly related to operation. Water flow from a pump is controlled by heat through a radiator, or fan speed blowing hot air out of a roof cavity during summer heat. It doesn’t mean the fan runs faster because your neighbour forgot to put his garbage bin out for collection. That’s a little too arbitrary for our purposes.

Overall, this idea is not too dissimilar to how a computer CPU fan works. Temperature feedback from the CPU is provided to the motherboard, which increases the fan speed as the temperatures increase, to ensure the CPU does not overheat.

In this situation you could use a thermocouple to keep an eye on temperatures. The PWM control could be setup to work on the water pump, the fan against the radiator, or both. When the temperature is measured below your preset level, you’ll have 0% PWM output. As soon as temperatures are detected above your target, the PWM will increase at a reasonable rate in order to maintain cooling at the required rate. Speed up the fan or pump (or both), the cooling effect through the radiator will be greater, retaining a cap on the maximum temperature.

This theory also works in reverse. While not so much a challenge in Australia’s weather, frozen pipes can wreak havoc on plumbing in colder climates, since water expands as it freezes. You can detect near-freezing temperatures, and circulate water through a heating element to prevent them from freezing. The system will basically be idle in summer, but work only as hard as necessary in the colder months.

While we're controlling pumps, in a cooling scenario you might find yourself controlling the cooler. Perhaps the pump and water flow doesn't change, but a thermoelectric cooler can have its power throttled according to the output requirements. It prevents the cooling device from not working harder than it needs to, preventing burnout and saving energy.

This approach is truly the most versatile, and has almost limitless applications. See the opposing page for a sample of how this type of system could work.

unrelated sensor


You may notice that we’re using 12VDC power for many things here. This is largely because many fans, pumps, and other devices run on 12VDC. There are more 5V devices available now that are easy to interface with Arduino, but 12V devices are still easier to obtain thanks to their use in automotive, boating, and computing applications. However this presents a challenge for sensor feedback when running from a 12V circuit. We’ll end up with 12V headed for our Arduino - not good!

To resolve this challenge, we use a simple resistor voltage divider to reduce this to acceptable levels. Only Build 1 uses this, but you may encounter more 12V sensors.

This reduced signal is then fed to two digital pins on the Arduino. Why two pins? We need some precise measurements so we monitor the rising edge of the feedback pulses on one pin and the falling edge on the other. This is explained a little more later.

It’s important to connect 12V to the Arduino’s Vin input, NOT the 5V input. This feeds power via its own 5V regulator, so you won’t see the smoke come out.

We also need a method to convert the 5V Arduino PWM output to something useful for a 12V device. We therefore feed the PWM from the digital pin through a series resistor to a Darlington transistor.

The transistor doesn’t need a heatsink as it is either completely off with no power used, or totally on producing a small voltage drop across the transistor, thus generating little power and heat. The transistor is in series with the load, and allows up to 5A of 12V power to be provided to the load, from the 5V PWM output of the Arduino.

We have also added a diode, which helps protect our circuit against back-EMF from the load. In practice, these should be installed across the motor terminals for best performance, but it still works on the breadboard too.

We also have a single LED which illuminates in response to the PWM straight from the Arduino. This provides a great visual guide as to what’s going on, and can be easily omitted if you don’t want it, since it’s purely a visual indicator. It can however, prove very useful for debugging purposes in the event you experience any difficulties (plus who doesn’t love LEDs?).

If you're moving these projects to a permanent application, further consideration should be given to back-EMF protection, over-current protection, short-circuit protection. However breadboard will no longer be appropriate then either.


This is fairly straight forward, with the touchscreen plugging into the Arduino Mega as a shield. However loading the test sketch can often avoid problematic debugging further down the line. From here, we can get our screen to display and check it is working appropriately.

Note, we are using a few libraries here. SPI, Adafruit GFX, Adafruit TouchScreen, and MCUFriend TFT Library. SPI is a pre-installed Arduino library; however Adafruit GFX and Adafruit Touchscreen, as well as the MCUFriend TFT libraries will have to be added. Fortunately they’re all conveniently available in the library manager. Simply go to Sketch -> Library Manager in your Arduino IDE. Search for the names and install each library one at a time.

Once you have completed the library installation and connected the display to the Mega, load the screen_test.ino code into your Arduino IDE and compile the code onto the Mega.

You should see the display fire up with the sample sketch. This sketch is designed purely for you to test the display. The up/down button will work, however provides no actual input/output changes. This will however, demonstrate how the display works and reacts to the user control for setting the target level.

In reality, the touchscreen shield only uses four pins, in addition to power. It’s entirely feasible to wire it without using the convenience of the shield, to free up access to unused GPIO pins. If you want to do this, simply connect as per the diagrams below. Make sure you have quality connections, or you’ll quickly find yourself with communication issues between the Arduino and the display shield. You’ll also need to update the code with any pin adjustments you make if using UNO or other hardware.


We're not yet producing an actual PWM output on any pins. This is purely designed to test the display, check that the touch functionality is working as expected, and generally help avoid troubleshooting problems later.

If you touch the screen controls up and down, you will see the displayed target values adjust accordingly. Since this is for demonstration purposes only, this sketch steps up and down in 10% PWM increments to make it more responsive. All other builds retain a finer level of control.

Note: The pinouts are for non-shield connection. The pinouts are generally the same between a MEGA and an UNO.

screen test

The Fundamental Build:

While it’s easy enough to use a potentiometer to set the desired motor speed and monitor the operation via Serial.print() statements, it’s not pretty and it’s not portable. We used a touch screen LCD panel (Jaycar XC4630) shield with an Arduino Mega. This particular display has powerful built-in graphic functions and a resistive touch screen, which makes developing a simple yet rich user experience, rather easy indeed.

The display is a shield, which means we ended up using a Mega because of the extra GPIO over an UNO, and installation is a breeze. We realise there are options that could have used less GPIO, however other screen options we looked at were more expensive than the additional cost of a MEGA anyway. If you have a touchscreen on hand which uses serial and want to use an Uno, you’ll just need to account for pinout changes.


The following build gets the basic working circuit up and running, which we can then utilise as a basis for the three practical implementation examples that follow.

Our TIP122 is a standard NPN Darlington Bipolar transistor to provide up to 5A of current to our PWM load. This is more than enough for the various loads we’re using, so you don’t have to change too much along the way for the other builds.

If you get this running, it's a few component changes and code modifications between the three applications we're presenting.

Parts Required:JaycarAltronics
1 × Arduino MegaXC4420Z6241
1 × 2.4” Touchscreen Display or SimilarXC4630Z6510
1 × 5mm Red LEDZT2292Z0800
1 × TIP122 TransistorZD0150-
1 × 1N4004 DiodeZR1004Z0109
1 × 330Ω Resistor*RR0560R7040
1 × 1kΩ Resistor*RR0572R7046
1 × 4.7kΩ Resistor*RR0588R7054
1 × 6.8kΩ Resistor*RR0592R7056
1 x 5.1kΩ Resistor*RR0589R7575

*Quantity shown, may only be available in packs. You will also need basic prototyping hardware such as a breadboard and jumper wires.

The sensor input adequately caters for 12V input using a voltage divider. This brings the signals down to a safe 5V for the Arduino. Once completed, you can load the "fundamental_pwm.ino" sketch. Adjusting the values on the screen should be reflected in the LED brightness, which reflects the PWM output. Then you can move on to Build 1. But first we'll look through some of the code.

fundamental build figure
Note: With the screen shield in place, it can be difficult to get to the Vin pin, which you can supply from the 12V to power the Arduino and screen. For prototyping it may be better to use USB power for the Arduino and Screen. However you'll still need 12V supply for the load and some sensors.

Pulsating PULSES

During development we found very high apparent rotation speeds with internal sensors. This wasn’t something we really considered when reading the tachometer output from a fan, for instance. When we connected an oscilloscope the issue became apparent. As we are effectively switching the 12V fed to the motor at about 1kHz, the feedback signal is “chopped” at the same rate. Without considering this we would see 60,000 or more revolution pulses each minute, when we know it's only capable of 10,000.

If we consider our ideal square wave signal again, both the positive (high) half, and the low half are equal. Now consider that we are turning the positive side on and off rapidly.

The answer is to ignore the short pulses and count only the low half cycles. The low half cycle is already “off” so it is not affected by the power being chopped. It’s just low for a certain time then goes high.

To determine the current rotation rate we use two interrupts: one that is triggered by the falling edge of the pulse, and the other triggered by the rising edge. Short (chopped) pulses are ignored.

The graph below shows a representation of what was received in the tachometer signal. The green blocks show the time period of the internal tachometer output. However the yellow lines show how it's actually returned as a choppy mess, due to the PWM supply itself.

fig 10


Before we get into each of the specific hardware builds, we’ll demonstrate how some of the code functions. There are tweaks to these for individual applications and different sensors, but the principles remain the same.


As the LCD display we’re using uses an Adafruit library, we first initialise that and then draw the GUI with the initial preset values. We then set our I/O pins, set the PWM output signal to a low duty cycle for a soft start, and configure the two interrupts. This sets up everything required for this sketch, and there’s no standard “loop” functionality.


This is called on the falling edge of the feedback pulses; in other words, when the energy to the device we are controlling is being turned off. It determines if the previous pulse was a real feedback pulse or caused by the PWM chopping. As the PWM chopping pulses are shorter than the feedback pulses, we can easily tell them apart and count only valid feedback pulses.


This is called on the rising edge of the feedback pulses (i.e., when energy is being supplied to the device we are controlling). It determines if five seconds has elapsed since we started counting pulses. If so, it determines if the speed is high, low or within a narrow range above or below the target. If the speed is higher or lower it adjusts the PWM rate to attempt to become within tolerance. It is likely that the feedback sensor or the device we’re monitoring will “wander” a little. You will see that as intermittent corrections to the PWM duty cycle, even though the load has not changed.


This is called from pulseComplete() during the “quiet” off or negative half cycle of the feedback signal. As its name suggests, it checks to see if the user has touched the up or down buttons on the GUI. If so, it displays the new target and calculates the new tolerance value.

There is a 500mS delay here that sets a maximum GUI update rate. Without this the target would be next to impossible to set as it would change too rapidly.

writeCurrentRPM(), writeSetRPM() and writePWM() are simple functions to update the displayed data on the LCD.


To get the most accuracy from our system we first need to determine the maximum speed of the device (fan, motor, anemometer, fluid flow sensor, etc). If this is not documented then we’ll have to work it out for ourselves. Ideally, we’d like to see one pulse per revolution of the device we’re controlling.

Some tachos (the feedback mechanism) produce more than one pulse per revolution. If you have access to an oscilloscope, you can examine the feedback pulses directly. Connect your device directly across the correctly rated power supply (12V, 5V, etc). This will give the fastest rotation rate and the highest pulse rate that we have to consider.

If you can’t access an oscilloscope then you can use the simple “pulse_counter.ino” sketch that we have provided. It will show the pulse rate on the serial monitor. This is a handy little sketch to perform this function easily - just be careful you aren't feeding a 12V signal into your Arduino - it can cause severe damage!

counter sketch

Depending on the type of sensor you're using, wether you're using liquids or gases etc, will determine how best to set things up. To get optimal results you may need to orient your device in a certain direction, and you need to ensure there are no kinked hoses or anything too.

Even simply laying the case fan on the desk, for example, actually puts a load on it and therefore affects the readings. In the case of the fluid sensor we used, the manufacturer recommends vertical orientation.

In the case of the fluid flow control sensor, we set up a large plastic container that holds around 40 litres of water. In this container we have a submersible water pump, the fluid flow sensor and plastic tubing to connect it. What we created was a not an electrical circuit, but a water circuit.

We had to determine how many pulses equalled, say, one litre of flow per minute. To determine this, we connected the pump motor to run full speed (connected directly across the 12V power supply). We then used a timer to find the time required to fill a 15 litre water bottle, which was 137 seconds. Two thirds of this gave us 92 seconds for 10 litres, which is easier to work with. The pulse rate from the tacho was 54Hz or 54 pulses per second. The total pulses for 10 litres is 54 x 92 or 4968 pulses. Let’s call it 5000 pulses. We now know that the flow of one litre through the sensor generates 500 pulses. Counting these pulses over time gives us the flow rate.

The precise details don’t really matter, since your hardware will likely be different to ours. However these sorts of processes will give you a method to setup the calibration.

When this is accurately configured, the serial monitor will give you a pretty good insight into how the code thinks and makes adjustments as required.

serial monitor

Build 1: Internal Sensor

To get our head around the fundamentals of operation, get our code running, and really just have a play, we’re going to use a 12V fan with tachometer output. This gives us a really easy way to keep a close watch on the speed of the fan.

Most fans will have a rated air-flow to RPM guide, which you could integrate into the display. But for now we’ll just use RPM, since that’s the input we’re getting from the tachometer.

Pumps with an integrated tachometer or flow meter appear to be less common. If you can’t find one, you can either use this example as a test, or skip to Build 2.

Additional Parts Required:JaycarAltronics
1 × 12VDC Fan with Tachometer OutputXC5054F2011
internal sensor

Load up the sketch "internal_sensor.ino" and compile to your MEGA. Your fan should automatically start spinning, and you should receive a readout on the screen.

Now here's a test. Lay the fan flat on the bench. This will create some additional resistance for the fan, and you'll quickly notice how the controller responds. You should see the detected RPM fluctuate and then level out again. However you'll probably notice that the Duty Cycle reading on the controller shows a higher duty cycle to maintain the requested fan speed.

Stand the fan upright again, and you'll see the reverse. The duty cycle should reduce down again. Depending on the fan, you may be able to achieve similar "friction" by pushing your finger onto the centre plate of the fan, which will try and slow it down. Depending on the torque of your motor, the results of this method will vary, however the net effect will be the same. Just watch out for your fingers!

This is the basics of how the automatic target-based control works. By monitoring the output (in this case the tacho from the fan) and self-adjusting the target based on your requirements, you achieve a more stable result.

internal sensor fritzing

Build 2: External Sensor

Monitoring the speed of the load is great, but as we touched on earlier in this project, measuring the result can provide better information about what’s going on. Measuring air speed, water flow, are all worthy points of interest to control our load from.

In this build we've changed from measuring what we're driving, to the water flow created by the load - since this is probably more of a real world application.

The code itself is very similar, however the tachometer signal coming from the water flow sensor is not "choppy" as in our first build since it has direct 12V power.

Additional Parts Required:
1 × 12VDC Water Pump
1 × Water Flow Sensor
2m Clear Hose
1 × Ball Valve
4 × Hose Clamps

Note: The hose, ball valve, and clamp specifications will depend on your pump and flow sensor. Other fittings may be required. With appropriate planning however, one trip to Bunnings usually suffices.

You may notice that we've removed the three resistors from the right hand side of the breadboard. That's because our flow sensor is a 5V unit. If you are using a 12V unit, you'll need to provide it with 12V power, and use the voltage divider included in the fundamental build to protect the Arduino.

In addition to the electrical build, connect the plastic hose between the pump outlet and the flow sensor. Along the line, also install the ball vallve. In general operation, this isn't really required, but it allows you to restrict the flow of water to see how the pump reacts. You'll need a bucket (or tub) of water too for your pump to draw from (you can feed it back into the bucket too).

Load up the sketch "external_sensor.ino" and compile. Your pump should start running and water should start flowing. Adjust the pump flow until you see around 50% duty cycle.

Now turn the ball valve gradually, to restrict the water flow. You'll see how the pump gradually increases in speed until the water flow is returned to the target. Obviously you can only restrict the flow so much before the water pump reaches 100% duty cycle.

In pratical applications, you won't use a ball valve, but some other effect (such as fluid viscosity changes) or downstream valves turning on and off. The system will constantly auto-adjust the flow rate within the bounds of its abilities, to maintain constant flow.

external sensor fritzing
Note: Schematic for this build is on the last page of this project.

Build 3: Unrelated Sensor

If your end goal actually has nothing to do with the flow rate, or whatever your load is producing, then an unrelated sensor is usually the way to go. For this build we’ll look at controlling our water pump with a temperature sensor (thermocouple).

Additional Parts Required:JaycarAltronics
1 × 12VDC Water Pump--
1 × Water Flow SensorZD1200Z6320
1 × DHT11 SensorXC4520-
2m Clear Hose--
4 × Hose Clamps--

Note: The hose and clamp specifications will depend on your pump and flow sensor. Other fittings may be required. With appropriate planning however, another trip to Bunnings will probably suffice.

Build the circuit as shown in the diagrams. Clear hose needs to be connected between your pump and flow sensor. A tub or large bucket of water is required as per previous builds.

fig 12
Note: Schematic for this build is at the end of this project.

If you have constructed Build 2 already, you only need to add the DHT sensor. The DHT11 sensor probably isn’t actually that practical for real applications, since it’s more of an environment sensor. A sensor mounted to whatever you’re trying to warm or cool (waterproof too), is probably more versatile. However you probably have a DHT11 sensor easily accessible, and you can easily manipulate it artificially yourself, which is great for testing.

Load up the unrelated_sensor_with_DHT.ino sketch provided in the resources. Note that it uses the DHT sensor library, which you can add via the Library Manager in the Arduino IDE if not already installed. Compile the sketch onto your hardware, and you’ll see we now have a slightly different display. In addition to everything else, we now have a temperature input. For this use, we don’t really care about the humidity, however if that’s relevant to your application you could easily read that instead.

You may also be thinking “why do we need the water flow sensor”. In actual fact, we don’t. However there are two benefits to leaving it in the system here.

  1. It gives you a very clear indication of the water flow going up and down in response.
  2. It could also be extended to provide a “flow stopped” alert, if there was no flow detected, and PWM output was higher than zero - indicating a possible failed pump or no water, etc.

With the Arduino running, you can adjust the “target temperature” via the touchscreen. Based on the ambient temperature, set the target temperature to somewhere around 15°C. Assuming you’re not working in a cold shed, this should see the water pump running at some sort of speed, since the measured temperature is already above what’s being measured.

Now we’re going to intentionally cool the DHT sensor. Grab a bag of peas, a few ice cubes, or whatever you have handy from the fridge or freezer. Put the DHT sensor near the cold objects (be careful it doesn’t get wet). You should see your measured readings coming down, at least to 15°C or less. Once this threshold is reached, the motor will shut off.

You’ll also notice that there’s a scale in the power control. The further away from the target temperature the measurement is, the faster the motor will run. Since we are dealing with a fixed point but have the flexibility of PWM not just a switch, we can introduce this scaled output, which a thermostat cannot do. This scaled output is handled with a simple definition of a COFACTOR.

#define COFACTOR 2

Depending on your application, you can easily adjust the co-factor to speed things up by a greater degree, the further the current temperature is from the target.

In our sample code, we simply use a percentage factor. If your target is 15°C, we treat this as 100%, to provide an easy baseline multiplier. If the temperature detected is 120% of the target (18°C), we run the PWM at 40% duty cycle, based on our temperature being 20% greater, and our cofactor of two. If it’s detected at 50% higher (22.5°C), then 50% with our cofactor of 2, will run the load at full power (that is, as near to 100% duty cycle as possible).

This cofactor provides you the ability to easily set a level at which the load will run at full speed. If you changed the cofactor to 1, the measured temperature would have to reach 30°C (200% greater target temperature

Of course, if the temperature measured is less than 100% of the target temperature, since water freezes at 0°C, we don’t really have to worry about negative targets for this purpose.

If you’re trying to heat rather than cool however, you simply need to change the COFACTOR to a negative number.

The maths will naturally invert, and your pump will run when the water is cooler, not warmer - EASY!

If you want a tighter degree of control (that is, the pump to achieve full speed with a smaller variation in temperature), you simply increase the cofactor.

#define COFACTOR 4

This will rapidly increase the ramp effect. Of course, increase the cofactor too high, and you really get behaviour more like a thermostat, as the duty cycle will increase too rapidly.

Take some time to mess about with the cofactor value and see what effects it has on your circuit. Depending on what you're monitoring, you'll find the sweet spot for how it behaves fairly quickly, once implemented into your setup.


There's loads of uses for this type of system, above what we've already covered with these concept proofs.

Many rural households using tank water will be familiar with water pressure switches. Effectively these cut in when pressure drops (i.e., someone turns on a tap), and cut out when pressure rises (i.e., someone turns the tap back off and the pump builds pressure back up a short time later).

If you were to replace the DHT temp sensor with a pressure sensor, you could actively monitor and respond to changes in water pressure along a pipe (ok, so really we're talking about water pipes in a caravan or something, this system probably isn't being implemented in an oil refinery pipeline!).

Alternatively, you may have a pump running in the traditional method (i.e., direct DC power), and this system can provide auxilliary pressure as required.

By only responding to a drop in pressure, the system can increase and decrease the pumps activity, only contributing enough additional pressure to maintain the overall system pressure. This would be useful in scenarios where water valves (i.e., - taps or solenoids) are automatically switched on and off for plant watering, as well as general use such as multi-bathroom houses where two people are showering at once and pressure gets upset quickly.


This project is ready to roll out to all sorts of applications, but these ideas can always do more, once put into a dedicated environment with specific requirements.

Redundancy in Loads

One thing we touched on briefly during the introduction, is the idea of redundancy. Instead of having a single water pump, you can have two water pumps running in the same system at a lower speed. So if one pump fails, the controller automatically detects the fall in water flow, and speeds up the operational pump to compensate. This could be done without any change to the hardware at all - simply connect both motors to the PWM output. However, it wouldn’t take much to add an alarm condition (such as a Piezo buzzer sounding) to alert you if one of the pumps fails.

A few precautions could be made, such as check-valves to ensure the water goes where you want it, and not back through a broken pump. You could also look at dual sensors; however, the reality of someone using these in absolutely critical systems is slim. Even though a DIY system may not be life or death, it may still be beneficial to implement redundancy to help avoid accidentally sacrificing hardware to the junkyard after something goes wrong.

Servo Control

Most of our suggested applications revolve around electrical loads, such as water pumps and blower fans. One very useful application however, could be for throttle control for combustion motors.

We published a feature in Issue 009 called “An Electrifying Tow”, where Edward Barnett used an electronic servo control system to regulate engine RPM in his tow mower (the throttle cable used to shake loose all the time). Our feedback controller could take this idea one step further. Simply programme in your desired RPM, and the controller will auto-regulate the RPM based on the tachometer input. Also, if you tied the input to a Ground or GPS-based speedometer, you could instantly have yourself a “cruise control” type system!

WARNING: This type of idea should not be implemented on a road-going vehicle, and all care should be taken even with a slow farm tractor or other vehicle. If something goes wrong in any instance where motion is automated, a serious risk of injury exists.