Hi, I am after some initial thoughts on a project I am considering. I have a saltwater reef aquarium. I have wave-maker pumps in the tank to provide flow. These are very good quality pumps that run silently & provide excellent current. The issue is that the controllers for these pumps are very limited in their options for programming variable flow. Far more expensive options use similar pumps but controllers that offer extensive options for flow rates variable with time.
All of these pumps are 24V DC, with a maximum current draw of 3A. They all have common 2 pole 5.5mm male jacks.
I would like to build an Arduino based controller with the correctly specified PWM motor controllers & power supplies to control up to 6 of these pumps, specifically I would like to be able to write code to allow each pump to have a variable flow rate cycle over a 24hr period, preferably being able to set outputs for specific times & the program ramps up or down linearly between these times.
I have looked through the available components & this seems possible to me, could anyone advise on what board & drivers I would need & how I would learn to write the code?
I have some experience with electronics & domestic electrical wiring & I am keen to learn coding & the use of Arduino for other projects, but I am completely new to this & have so far not purchased any components.
Thank you in advance for any help or guidance you are able to give.
Motor drivers over 2a are expencive and can easily be made for fare cheaper, maybe using something like an IRF2804, can handle up to 40v 75A and can be wired up with minimal components.
The IRF2804 is not a dedicated PWM motor driver, but rather a power MOSFET transistor. It is designed for high-power switching applications and can be used as a component in a motor driver circuit.
To drive a motor using the IRF2804, you would typically need additional circuitry such as a microcontroller or a dedicated motor driver IC. Here's a basic example of how you could use the IRF2804 in a PWM motor driver circuit:
- Connect the source pin (S) of the IRF2804 to the ground reference of your circuit.
- Connect the drain pin (D) of the IRF2804 to one terminal of your motor.
- Connect the other terminal of your motor to the positive power supply.
- Connect a flyback diode across the motor terminals, with the cathode connected to the positive power supply and the anode connected to the drain pin (D) of the IRF2804. This diode helps to protect the transistor from voltage spikes generated by the motor during switching.
- Connect a gate resistor (typically around 100-1,000 ohms) between the gate pin (G) of the IRF2804 and the output pin of your microcontroller or motor driver IC.
- Connect the gate pin (G) of the IRF2804 to the output pin of your microcontroller or motor driver IC.
- Optionally, you can add a pull-down resistor (around 10-100 kilohms) between the gate pin (G) and the ground to ensure the transistor turns off when the microcontroller or motor driver IC is not actively driving the pin.
With this setup, you can use pulse width modulation (PWM) signals from your microcontroller or motor driver IC to control the speed and direction of the motor. By adjusting the duty cycle of the PWM signal, you can control the average voltage applied to the motor, thus controlling its speed.
Ive used these as drivers for 3d printer hotends running @240+c and heavy loads, ive NEVER had one fail. "knock on wood"!.
Here is a (hopefully) working example with your needs as you described with comment explinations.
// Include the necessary libraries
#include <Wire.h>
// Define the motor control pins
const int motorPins[] = {3, 5, 6, 9, 10, 11}; // Modify this array based on your motor controller connections
// Define the flow rate settings (0-255, where 0 is off and 255 is maximum flow)
const int flowRates[] = {0, 128, 255, 128, 0, 0}; // Modify this array to set your desired flow rates
// Define the ramping time in milliseconds
const int rampTime = 60000; // 1 minute ramp time, modify as needed
// Define the number of pumps
const int numPumps = sizeof(motorPins) / sizeof(motorPins[0]);
// Define the start and end times for each flow rate segment
const int numSegments = 3; // Modify this based on the number of flow rate segments you want
const int segmentTimes[numSegments][2] = {
{0, 8}, // Start at 0 seconds, end at 8 seconds (example segment 1)
{8, 16}, // Start at 8 seconds, end at 16 seconds (example segment 2)
{16, 24} // Start at 16 seconds, end at 24 seconds (example segment 3)
};
// Variables for tracking time and flow rate
unsigned long startTime;
unsigned long elapsedTime;
int currentFlowRates[numPumps];
// S-curve parameters
const float sCurvePower = 3.0; // Modify this to adjust the curvature of the S-curve
void setup() {
// Set motor control pins as OUTPUT
for (int i = 0; i < numPumps; i++) {
pinMode(motorPins[i], OUTPUT);
}
// Initialize the flow rates and start time
for (int i = 0; i < numPumps; i++) {
currentFlowRates[i] = flowRates[0];
}
startTime = millis();
}
void loop() {
// Calculate the elapsed time since the start
elapsedTime = millis() - startTime;
// Update the flow rates based on the time
for (int i = 0; i < numPumps; i++) {
currentFlowRates[i] = calculateFlowRate(elapsedTime, i);
analogWrite(motorPins[i], currentFlowRates[i]);
}
// Check if the ramping time has passed
if (elapsedTime >= rampTime) {
// Reset the start time and flow rates
startTime = millis();
for (int i = 0; i < numPumps; i++) {
currentFlowRates[i] = flowRates[0];
}
}
}
int calculateFlowRate(unsigned long time, int pumpIndex) {
// Find the current segment
int segment = 0;
for (int i = 0; i < numSegments; i++) {
if (time >= segmentTimes[i][0] * 1000 && time < segmentTimes[i][1] * 1000) {
segment = i;
break;
}
}
// Calculate the interpolated flow rate within the segment using the S-curve algorithm
unsigned long segmentStartTime = segmentTimes[segment][0] * 1000;
unsigned long segmentEndTime = segmentTimes[segment][1] * 1000;
int startFlowRate = flowRates[segment];
int endFlowRate = flowRates[(segment + 1) % numPumps]; // Wrap around to the first flow rate after the last segment
float t = (float)(time - segmentStartTime) / (segmentEndTime - segmentStartTime);
float sCurveT = pow(t, sCurvePower) / (pow(t, sCurvePower) + pow(1 - t, sCurvePower));
int interpolatedFlowRate = startFlowRate + (int)(sCurveT * (endFlowRate - startFlowRate));
// Map the interpolated flow rate to the IRF2804 PWM range (0-255)
int pwmValue = map(interpolatedFlowRate, 0, 255, 0, 255);
return pwmValue;
}
In this code, the calculateFlowRate()
function uses the S-curve algorithm to interpolate the flow rate within each segment.
The parameter sCurvePower
controls the curvature of the S-curve.
Higher values result in a more pronounced curvature, while lower values result in a smoother transition.
Adjust the sCurvePower
value to your preference to achieve the desired flow rate transition.
Also, make sure to provide appropriate heat sinking for the IRF2804 MOSFETs.
Jmtc.
Right. Most motor controller boards are reversible which means they need 4 MOSFETS (or the equivalent of 4 MOSFETS). On the other hand, it's easier to find an assembled board.
Here is a motor driver schematic. If you build it, start by building & testing one.
Start simple and "develop" your code a little at a time. And since you can also control/dim LEDs with PWM, I'd recommend developing your code with LEDs and hook-up the motor controllers later. And of course, you can use shorter cycle times during development.
Take a look at some of the examples and look-through the Language Reverence. (The language reference won't make a lot of sense if you haven't programmed before but it's still a good idea to look at the basic instruction set.)
The Blink Example is the "starting point". It can blink the built-in LED so it doesn't need any extra hardware. It's a good check to make sure you can download & run a program.
I start all of my programs with Blink (or some other simple known-working code) just so I'm starting with a complete working program that I can edit, and of course I usually take-out the blink part once I get started.
The Blink Example can also "pulse" a motor on & off, but you'll probably want slower timing (longer delays).
The Fading Example shows you how to fade/dim an LED or speed-up & slow-down a motor. Again, you'll probably want to slow it down for a motor. In case you don't know this, analogWrite() is PWM, not true analog (and in this case PWM is what you want).
In your real program you'll want to avoid delay() (or at least long delays or multiple delays). Processing pauses during delay() so your program can't do anything else. For example, if you want to fade two or more LEDs at different rates you can't use delay() because they each need their own separate timing.
The Blink Without Delay Example shows you how to do timing related things without pausing the program.
The "trick" to blinking (or dimming) more than one LED (or controlling more than one motor at a time) is to make more than one previousMillis and interval variables. i.e. You can make previousMillis1, previousMillis2, interval1, interval2, etc. (There is only one currentMillis.)
Also see Demonstration code for several things at the same time.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.