Disc1 Arduino Doser

The pumps probably take DC. SO you will have to have some sort of transformer. A wall wart will do. In my project the pumps were 12VDC. So if you were using a MOSFET transistor the positive would go to the pump. The other side of the pump goes to the MOSFET drain, the source goes to ground. The base gets the signal from the arduino. You need to protect arduino and the mosfets from the kick-back voltage from the pumps. The easiest way to do this is to put a diode backwards between the ground from the pump and hot. That way if the positive voltage goes below 0, like on start or stop the pump, the diode acts like a short to ground. Without something like that, arduino will reset or lock up every time the pump runs.

Look at the right side of the schematic in post #7. The rest of that stuff on that pic is just to be able to use a rotary encoder instead of buttons. The right side towards the top has the two transistors.
 
I'm trying to look at the diagram you included in post #7 but it shows up pretty small. Could you attach a larger version (or send it to me in an email if that works better?).

I want to review it and see what I can learn from it.

Thanks!
 
did you solve the rollover problem ?
currently working on a arduino dose project but using millis theres a rollover every 49-50 days that can cause problems.
 
Check this link. http://www.faludi.com/2007/12/18/arduino-millis-rollover-handling/

Look close to the bottom and there's a comment that explains how to use signed variables to handle rollovers. This is useful if the rollover might happen a second time before you check it again. I am assuming that with a dosing pump that will not be the case. Your program will probably check the time often.




The absolute easiest way to handle roll-over of a timer if it's not going to happen multiple times during before you can deal with it is to simply check the time against some old time. You simply test the current time against some previous time. If there has been a rollover, you will suddenly get the new time being less than the old time. It looks like we've gone into the past. Then it's just a little math to fix the times back up and we can put that into a if-else or even a separate time checking function.

If a rollover hasn't occured, then the new time will always be greater than the old time. If that's the case, then no rollover has occured and you don't need to fix anything.

Either way it goes down, at the end of checking the time, set the variable holding the old time to the new time so you can check against it next time.



I don't know if there is an interrupt vector for millis rolling over. If there is, that would be another option.
 
thanks for your reply.
It seems like an easy and smart solution.
I ended up with this in my α0.4 version of the code.
I'm quite new to arduino.......


// dosepump a
int pot_vala, pot_vala2, dosea, motor_speeda, motor_inta ;
currentTimea = millis(); // get current time
if(currentTimea >= (loopTimea + 3600000)) // dose once an hour
dosea=1; // dose on
loopTimea = currentTimea; // Updates loopTime
if(currentTimea >= (loopTimea + motor_inta)); // adjuastable duration of dose
dosea=0; // dose off
if(currentTimea < loopTimea); // rollover protection
dosea=0; // dose off
pot_vala = analogRead( dosepumpa ); // speed
pot_vala2 = analogRead( dosepumpat ); // duration
motor_inta = pot_vala2*255.0/1023.0; // duration
motor_speeda = pot_vala*255.0/1023.0; // speed
if (dosea ==1) analogWrite(motor_pina, motor_speeda); // output to servo controller
Serial.println("dosepump a");
Serial.println(motor_speeda);
Serial.println(motor_inta);
 
The only problem I see with this one is that motor_inta is set by an analog read and then mapped to 0 - 255. That means the largest motor_inta can be is 255ms. You're going to want the pump to be able to run for more than a quarter of a second.

Pick the maximum time you want the pump to be able to run and map onto that value. To save size on the variable, you can just store the number of seconds and multiply motor_inta by 1000 when you check it against the time.
Code:
if(currentTimea >= (loopTimea + (motor_inta*1000))); // adjuastable duration of dose
and:
Code:
motor_inta = pot_vala2*300/1023.0; // duration
with these two lines replaced, the maximum pump time would be 300 seconds or 5 minutes.


PS. Check out the constrain and map functions in the Arduino Reference.
 
So, there was a little.... ahem....:uhoh3: saltwater incident with my dosing setup. Long story short, I'm down one Arduino UNO. I also don't have a serial enabled LCD anymore. :sad2:

Rather than order a new LCD, I'm going to use one that I have here. But this one isn't serial enabled. The old one used Rx and Tx and Serial.print. This one has to use the LCD library, and takes a whole bunch of pins.

So here's the solution. I'm going to put it on SPI. I have some pin extenders and other components that all speak SPI, so that's the natural way to go. If I need the four pins back, I can add on a pin extender at a cost of a single pin.

I'm going to take a 74HC595 8-bit shift register and connect the output pins in order to the data pins of the LCD 0-7. The SCK (pin 13) will go to the 595's clock. The MOSI (pin 11) is going to the data input on the 595. I'm going to use pin 10 for the enable pin on the LCD and also for the RCK on the 595. RCK puts the data from the shift register into the output register. Since I will have the OE (output enable) tied to ground the ouput will immediately show up on the pins as soon as I pulse RCK. Since the 595 is faster than the LCD, the same pulse gets the output onto the pins before the LCD reads it. So the same signal also serves as the Enable line on the LCD.

I'm going to do the SPI in 8-bit mode, just out of personal preference. I could have used 4-bit and saved one pin on the Arduino, but the code would be more involved and I think I am going to end up adding an 8-pin extender eventually to this project.

Since I'm using all the pins on the 595 for the 8-bit input, I have to use a pin on Arduino for the RS pin to the LCD. I'm going with pin 8 for right now.




Also, since I'm going to be inside the code and rebuilding the circuit, I figure I might as well get that stupid speed sensor out and put a proper rotary encoder in. The one I have doubles as a push-button. So it may end up being the only control I need. I need the pins anyway since I am going from 2 to 5 on the LCD. This one will only take 2, where the old one took 4.

And I might as well bring it up to Arduino 2.2 as well. Some of the template functions won't format in 2.2 so I'm going to move them to the C++ portion.



This got me to thinking about more to do while I'm under the hood. I don't like the way I have the schedule being input. I think I just want start time and stop time and an interval. And I want an option to set one schedule off the other so I don't have to input them both. That should be easy enough.

I'm also changing the time of day math from long to int and using minutes past midnight instead of seconds. Do I really need second by second resolution on my dosing times? I don't think so. By using int instead of long, I am saving myself almost 50% of the size of the schedule.



The last idea, and this one really got me thinking, was to save myself one more math step and make it so I can input my water volume and my alk recipe and put the dose in alkalinity units. Say, add 0.5dkH per day instead of add 60mL per day. That would be pretty simple math. Something to think about, but it would be one step towards a doser that you only have to input your test results into and it figures out the dosing to hit your targets for you. That might be cool. It tells you that you need to test, you input the result, and it alters the dose or does a booster if necessary. Hmmmmm.....
That might make this not such an overkill project of a doser.

Thoughts???
 
I'm a little confused in respect to where to put the diode for feedback in relation to the mosfet. What is the line that goes down and right from the mosfet that is labeled pump neg. I thought pump negative is the one that is going to the ground.

Where do I put the diode? is it a separate/additional circuit loop that bypasses the mofset?

Thanks!
 
He powers the pump with the plus side always.

To run the pump you need to ground the other side.

But! If he just grounded it it would run full blast forever!

So instead you run that pump lead to the MOSFET. The other side of the MOSFET is the thing tied to ground.

Then AND ONLY WHEN, the MOSFET is activated the pump lead is grounded thru it.
 
It goes right from the pin on the collector pin of the mosfet where the pump's ground wire connects and goes to the 12V+ power rail. It should be reverse biased, so the tip of the arrow (the ring on the diode) goes towards the positive rail.


And kcress is exactly right. Those are N-channel MOSFETs, so they sit between the pump and ground. The pumps are connected directly to the 12V+ positive rail.
 
Last edited:
You could alternatively put it across the actual connections on the pump. It would still go with the ring towards the positive side.
 
Oh man did I ever just find an easier way to do this.

Scheduling, we've been going about it backwards. Something that BeanAnimal said on one of nrbelk's other threads has been stuck in my head for a long time. The "Aha" moment came when I realized the important thing isn't the timing it's the volume.

We only need to keep up with a tally of how much has already been added today, and the time of the last dose we made so we can space them by some minimum interval. There are no arrays, no lists, no flags to keep track of, and no complex algorithms. We only need a function that returns whether or not a number is between two other numbers and a funtion that can tell the difference between two numbers. By building these two functions in a way such that they can handle the rollover issues, then none of the rest of the code needs to worry about midnight.

Simply put, the logic should work like this. If it has been long enough since the last dose AND we still have some volume to go AND the time is between the daily start and end times, THEN make a dose. Then just keep track of the volume.

So this way, I just set a start time, and end time, a volume and an interval. The program takes those four and calculates the smallest dose that fits and thats it. Nothing is actually scheduled, i just keep a variable volume_dosed that keeps up with how much we've done today and compare to a variable total_volume that holds the total volume for the day. Once those two match up, then no more doses no matter what.

This will protect us from missed doses and over doses due to timing issues when the program gets bigger. And it takes way less memory of keeping track of a list of times. Most importantly, it protects us from doses piling up and dumping all at once if some problem stops them from running for a while.

There are some issues with this if the interval to check the schedule isn't a factor of the dosing interval. You end up being off by a few minutes each dose which adds up to a missed dose if there are a lot of them. This is a particular problem if either interval is a prime number. Right now I'm working around that by checking every minute, but it could easily be fixed with a little math. Or more easily fixed by allowing a single extra dose after the dosing window that catches the volume up if any was missed. Or what I will probably do is recalculate the minimum dose every time and allow the dose to be variable. So if you miss a dose you make it up a little at a time over the rest of the period. Either way, it's all about the volume dosed today and the total daily volume. The actual time isn't even considered, only the interval to the last dose.


The only other question is when to reset the volume_dosed variable. Right now it happens at midnight, but it also makes sense to do it at the start_time. It depends on whether you want to think about it as a daily volume or a dosing window.







I've finished fixing up most of the things I mentioned fixing and I have new code that compiles (still having to use 2.1 because of that template bug) but I haven't run it through it's paces on the board. All the little pieces work, but it hasn't been tested together. I'll get the current code in a few days. It's a boatload easier to follow and is well commented.
 
nice! Can't wait to see the code to see how it works!

I'm getting closer to finishing up my pumps. Going to go get the diodes today.
 
Back
Top