How To Go Slower
With the current setup 1 pps is roughly 0.45 ml/hr. To go slower than this rate is simple: pulse at a lower rate.
There are two main ways that can be achieved:
- slow down the ISR timer
- use a longer array
Instead of iterating through the array every millisecond, process it every 10 or 100ms. This is quite easy to do by changing the IRQ parameter that initializes the timer. Note that the timeout does not have to be a multiple of 10 or an even number at all. It simply has to be a very regular, consistent interruption.
The only caveat is that at very long timer values, the pulse train going to the stepper could "jitter" and not be as smooth as possible. My guess is that anything more than 100ms or so is the maximum value for the timeout. This translates into a flow rate that is roughly 100 times slower than I can get (0.45) right now: 0.0045 mL/hr.
Using a longer array is probably the better option. Right now the array length is 1000 entries. With 10,000 entries, I could achieve a flow rate which would be 10 times slower. The problem is that the Arduino Mega only has 8k RAM available. The max size of the array then is slightly less than 4K bytes since:
- there are other variables in the code that take up some memory
- when an incoming command comes in, I fill in a 1K buffer and then if all is well, I copy that entire buffer over to the array, i.e. I need twice the RAM for a given array size
In reality, after all is said and done, I will probably bump the array to 3K elements and also slow down the timer to 3ms or so. That gives me a (3 * 3 == 9) factor slower pulse rate, that is 0.050 ml/hr which is just under my goal of 0.1 mL/hr. I could slow down the timer to 30ms and thereby achieve (3 * 30) factor which is 0.005mL/hr and that is under the longer term goal of 0.01 mL/hr.
In all of this, I do need to worry about the higher end. The array elements are bytes, therefore the max value in each element is 255.
Translate PPS to Fluid Rate
At this point, I have a system that accurately and fairly precisely pulses the stepper at a given PPS rate. But the User of this system is more interested in fluid rate, not pulses-per-second. This brings up two questions:
- how can I derive a formula that translates from expected fluid rate to PPS
- how accurate is that formula?
The Formula
The simplest way to get a formula is to perform a series of tests and use linear regression to get the best fit formula to translate from expected Fluid Rate to PPS. The methodology is:
- Do the following for a significant set of samples across the entire range of PPS available (1 to 6000 PPS say)
- run a test at that PPS
- measure the actual fluid rate using a high accuracy scale
- Add all data points to a spreadsheet, i.e. actual rate vs PPS value
- Calculate a linear regression formula and the R2 value for the data; check the R2 value indicates a good, close fit
- Double-check the formula:
- enter an expected rate into the formula
- send the resulting PPS to the motor
- measure the actual fluid rate using a high accuracy scale
Formula Accuracy
A few notes based on the methodology above:
- "significant set of samples"
- in short the more, the merrier. But note that at low rates the tests take a long time so there is a trade-off.
- "measure the actual fluid rate"
- this is quite difficult at rates below 5mL/hr or so see Scale
- "linear regression fit"
- could use 1st, 2nd or higher order linear regression. Use R2 to choose one. Watch out for over-fitting.
- "Calculate fluid per pulse"
- one available double-check is to calculate the fluid per pulse at the various rates.
- For each motor pulse, the peristaltic pump turns very slightly but roughly the same amount each time.
- Averaged out across a few thousand or more pulses, that value should be consistent. In my case it was roughly 115 - 119uL/pulse measured over the rates ranging from 1 mL/hr to 2200 mL/hr.
- "Multiple motors"
- Should test across multiple motors. Right now it is, after all, a sample size of one.
- "Multiple pump heads"
- Should test across multiple pump heads. Different heads may have different roller mechanics and so have different, better(?) results.
- "Multiple pinch tubing"
- should test across multiple samples of the tubing used in the peristaltic pump.
- Multiple Arduinos
- Should test across multiple Arduino boards.
- The IRQ timer consistency is important. If it is interrupted every 1.003ms say, it should be that value across multiple Arduino boards.
- e.g. the crystal oscillator used to set the Arduino clock may not be accurate/precise across different boards