 |
|
 |
| Parallax Forums > Public Forums > BASIC Stamp > Accurate measurment of long time intervals | Forum Quick Jump
|
|  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/8/2006 8:29 AM (GMT -8) |   | Hi,
We are designing a fraction collector (automated collection of effluent from soil columns) which is based around a BS2 and serial stepper motor controller. A simple outline of how the device is supposed to work is as follows:
1. init motor controller
main: 2. poll for user input (4 buttons) 3. display contents of timing variables (time between cycling a collection vessel) on serial LCD
4. if the user has pushed the 'start' key, start counting out time intervals specified in the program, and optionally modified by buttons. 5. check elapsed time, and rotate fraction collector carriage a single step.
goto main
The main problem is that while counting out time (with PAUSE or SLEEP) the BS2 can't really do anything else, and we would want to constantly be polling for user input on some buttons, and updating the LCD.
I have taken a look at the "pocket watch b" module, and wonder if polling this device in every loop of the main subroutine might work for couting out long time intervals (10mins to 2 hours)...?
Note that the single motor controller will be used to address 3 stepper motors, thus three timing variables will be used to decide when it is time to rotate the fraction collector carriage.
Any thoughts or ideas would be appreciated!
Cheers,
Dylan | | Back to Top | | |
  |  Vern Graner Nuts & Volts Columnist

       Date Joined Oct 2004 Total Posts : 327 | Posted 2/8/2006 10:00 AM (GMT -8) |   | DylanB said... The main problem is that while counting out time (with PAUSE or SLEEP) the BS2 can't really do anything else, and we would want to constantly be polling for user input on some buttons, and updating the LCD. Don't know if this will be helpful, but I've used the Pocket Watch B and have set an "alarm time" on the unit. Then, you can make a "DO WHILE" loop contingent on the state of the alarm pin, when that pin state changes you know that the pre-set time has elapsed.
Another method I've seen used is to "roll your own" pause command by creating a subroutine and then placing the polled item in a loop. So instead of placing a "pause 100" command in the middle of your program, set a variable and call a loop with the sensor check and a pause together. Here's some pseudo-code to (poorly) demonstrate what I'm getting at:
cntI VAR Byte ' Counter DELAY VAR Byte ' number of miliseconds to wait MOTOR PIN 1 ' Pin where motor is connected SENSOR PIN 2 ' pin where sensor is connected
'Main Code :AGAIN HIGH MOTOR DELAY=100 GOSUB WorkingPause GOTO AGAIN
'Subroutine for a "Working" pause WorkingPause: FOR cntI=1 TO DELAY IF SENSOR=1 THEN RETURN PAUSE 1 NEXT LOW MOTOR RETURN
The idea is to make the sensing or "work" portion of the code "interleaved" with the pause statement so instead of a "Pause 100" use a "pause 1 and Check Sensor" in a 100 count loop and call the loop instead using a "pause" command.... Not really elegant, but it can avoid having the stamp "sleeping" when it could be doing work... 
Vern Vern Graner CNE/CNA/SSE | "If the network is down, then you're Senior Systems Engineer | obviously incompetent so why are we Texas Information Services | paying you? Of course,if the network http://www.txis.com | is up, then we obviously don't need Austin Office 512 328-8947 | you, so why are we paying you?" ©VLG
Post Edited (Vern) : 2/8/2006 6:07:41 PM GMT | | Back to Top | | |
   |  Kevin Wood Registered Member
        Date Joined Aug 2004 Total Posts : 768 | Posted 2/8/2006 8:01 PM (GMT -8) |   | You could always use a seperate DS1302 for each motor. I think this would be easier to keep track of the timing, since you could reset each clock after the motor advances, and wouldn't have to get code-happy with the timing math. Just keep polling the inputs and clocks as needed.
Also, because of the timing intervals, you might want to stagger the initial motor starts by a minute or so. Otherwise, I think worst case scenario would be all three motors conflicting every 40 minutes or so. | | Back to Top | | |
  |  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/8/2006 11:19 PM (GMT -8) |   | Thanks for the quick reply Chris.
Here is a little bit more info on the project. We have 3 stepper motors, each attached to a circular test tube rack. A single test tube is positioned under a soil column, and effluent is collected in the test tube. Based on the nature of the soil, and thus the rate of effluent discharge, the test tube rack under the soil column must be advanced 1 test tube every time interval. this time interval can be specified in the program sent to the BS2 (based on some initial guesses), and then later adjusted up or down with some buttons connected to the BS2. Since the three soils are not quite the same, the time interval between advancing the test tube rack for each setup may be different.
Therefore, once the device has been started, motor1 will need to be advaced every dt1 interval, motor 2 will need to be advanced every dt2 intervatl, and motor 3 will need to be advanced every dt3 interval.
a simplified flowchart might look like this:
1. init motor controller
dt1 = 10minutes dt2 = 15minutes dt3 = 30minutes
main loop: 2. update an LCD 3. poll buttons for adjustments to time intervals 4. when start button is pressed, start timer and enter running loop
running loop: 5. poll for adjustements to dt values 6. update LCD
check elapsed time
if elapsed time since last activation of motor1 >= dt1 advance motor 1 if elapsed time since last activation of motor1 >= dt2 advance motor 2 if elapsed time since last activation of motor3 >= dt3 advance motor 3
goto running loop
advancing the motors is accomplished by sending some serial data to a motor controller, which addresses each motor.
My thoughts on using a single clock: it would be more elegant if we can do it this way, but i am worried about losing precision due to integer math on time durations- but maybe this is not an issue. It sounds like the smallest time interval that we need is 1 minute.
thanks again,
Dylan | | Back to Top | | |
 |  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/8/2006 11:23 PM (GMT -8) |   | Also- the BS2 is only sending a motor "advance" command to the motor controller -- i.e. tell the motor to move to position 2000 at speed x at acceleration y -- the motor controller then figures out the hard stuff, and turns off the motor when it has reached position 2000
dyan | | Back to Top | | |
  |  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/12/2006 5:34 PM (GMT -8) |   | Chris,
Thank you for the helpful hints. We ordered 3 DS1302 units + crystals. The sample code for interfacing to a single RTC seems like it will be a good starting point. Which inputs/outputs can be shared between all three RTC units? Is there any sample code for this floating around somewhere perhaps... ?
Thanks!
Dylan | | Back to Top | | |
  |  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/25/2006 4:09 PM (GMT -8) |   | Chris,
Your code and hints have been most helpful!
We were successful in implementing the 3 independent DS1302 chips, using only 5 I/O lines as you suggested.
Now we have a new bug to squash... When the three clocks are started at the same time... well almost the same time with a FOR loop:
FOR idx = 0 TO 2 mins(idx) = $00 secs(idx) = $00 GOSUB Set_Time NEXT
Set_Time: ' DS1302 Burst Write HIGH rtc(idx) ' Select DS1302 SHIFTOUT DataIO, Clock, LSBFIRST, [WrBurst] SHIFTOUT DataIO, Clock, LSBFIRST, [secs(idx), mins(idx), hrs(idx),date, month, day, year, 0] LOW rtc(idx) ' Deselect DS1302 RETURN
... the clocks appear to stay in sync:
'get the time by updating our time variables GOSUB Get_Time
'update the clock display on the LCD SEROUT LCD_serial_pin,LCD_serial_setup,[254,71,1,1, " ", HEX2 mins(0), ":", HEX2 secs(0), " ", HEX2 mins(1), ":", HEX2 secs(1), " " , HEX2 mins(2), ":", HEX2 secs(2), " "]
Get_Time: FOR idx = 0 TO 2 ' DS1302 Burst Read HIGH rtc(idx) ' Select DS1302 SHIFTOUT DataIO, Clock, LSBFIRST, [RdBurst] SHIFTIN DataIO, Clock, LSBPRE, [secs(idx), mins(idx), hrs(idx), date, month, day, year] LOW rtc(idx) ' Deselect DS1302 NEXT RETURN
...however, we are resetting individual clock units when a specific delta-time has elapsed
'reset clock 2 idx=2 mins(idx) = $00 secs(idx) = $00 GOSUB Set_Time
Set_Time: ' DS1302 Burst Write HIGH rtc(idx) ' Select DS1302 SHIFTOUT DataIO, Clock, LSBFIRST, [WrBurst] SHIFTOUT DataIO, Clock, LSBFIRST, [secs(idx), mins(idx), hrs(idx),date, month, day, year, 0] LOW rtc(idx) ' Deselect DS1302 RETURN
I have noticed that each time i reset a clock, it loses a small amount of time relative to other clocks that are still running. - possibly due to the fact that resetting a clack takes a small amount of time.
i am wondering if there is perhaps a more efficient way of accomplishing this task, i.e. some math that can be done to determine if a delta-time unit has elapsed, without having to reset the clock units.
attached is a complete listing of the program
Thanks!
Dylan
File Attachment : main_v1.bs2 8KB (application/octet-stream)This file has been downloaded 159 time(s). | | Back to Top | | |
  |  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/25/2006 6:55 PM (GMT -8) |   | Chris,
Starting all clocks at 00:00.
if i reset: clock 0 every 15 sec clock 1 every 30 sec clock 2 every 45 sec
...then clock 0 will lag behind clock 1 which will lag behind clock 2.
i.e. near 15 seconds this is what the clocks should read 00:14 00:14 00:14 00:00 00:00 00:30
and they do.
i.e. near 30 seconds this is what the clocks should read 00:14 00:29 00:29 00:00 00:00 00:30
and they do.
i.e. near 45 seconds this is what the clocks should read 00:14 00:14 00:44 00:00 00:15 00:00
and they almost do: clock 0 appears to increment _just after_ clock 1 and 2
i.e. near 60 seconds this is what the clocks should read 00:14 00:29 00:14 00:00 00:00 00:15
and they almost do: clock 0 appears to increment _slightly after_ clock 1 and 2
i.e. after 75 seconds this is what the clocks should read 00:14 00:14 00:29 00:00 00:15 00:30
and they almost do: clock 0 appears to increment _slightly after_ clock 1 and 2
i.e. after 90 seconds this is what the clocks should read 00:14 00:29 00:44 00:00 00:00 00:00
and they almost do: clock 0 appears to increment _slightly after_ clock 1 and 2
.... and so on. the longer i let it run, the more "behind" clock 0 and then clock 1 become relative to clock 2 .
in summary, after a total time duration of 100 minutes = 6000 seconds, the clocks have been reset: clock 0: 400 times clock 1: 200 times clock 2: 133 times
seems that every clock reset operation makes each one of these three clocks slightly slower than an outside time source, porportional to the number of reset operations. I wonder if there is some way to compensate for this...
As far as savinf some space goes. How exactly would I implement a single SHIFTIN operation such that it read in data from each clock ?
Thanks!
Dylan | | Back to Top | | |
    |  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/27/2006 12:06 PM (GMT -8) |   | Just for the record, this forum has been a great help to this project! I will post some pictures of the _nearly_ complete setup later this afternoon.
Dylan | | Back to Top | | |
 |  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/27/2006 1:01 PM (GMT -8) |   | here is a link to some pictures to describe the device that this thread was started for: http://169.237.35.250/~dylan/fraction_collector/
Cheers, | | Back to Top | | |
 |  Tracy Allen Registered Member

       Date Joined Jul 2004 Total Posts : 2845 | Posted 2/27/2006 2:41 PM (GMT -8) |   | Hi Dyan,
Nice project!
For the math, the first thing need to know is the "//" operator. In Stampese, that means, "remainder after division". In my example, period1 is equivalent to your dt_1, that is, how often you want the motor to turn on.
in this code
motor1flag = minOfDay // 10 MAX 1 motor2flag = minOfDay // 12 MAX 1 motor3flag = minOfDay // 15 MAX 1
the three independent flags will equal zero once every 10, 12 and 15 minutes respectively, and 1 at all other times. That is because minOfDay // period is the remainder of the divisions, e.g., 29 // 15 = 14 30 // 15 = 0 31 // 15 = 1 32 // 15 = 2
The MAX operator restricts the value to either zero or 1.
The actions as written occur exactly matched with clock time. That is, with 10 minutes it would happen on the hour, 10 minutes after the hour, and so on, and with 12 minutes, it would also be on the hour, 12 minutes after the hour and so on. That might be what you want.
However, if you want an arbitrary origin for starting each interval, then you need phase1, phase2, phase3. Say you want to start a 10 minute interval for motor 1 at 7 minutes after the hour of 2am. The value of minOfDay at that time is 127, and the remainder when divided by 10 is 7. Set phase1 equal to that value. Subsequently, the motor1flag will equal zero at 137, 147, 157,... motor1flag = minOfDay + 7 // 10 which you would use with variables instead of constants for 7 and 10. The phase1=7 is the starting phase with respect to the 10 minute cycle.
If you restrict your time intervals to numbers that evenly divide 1440 minutes, then that is all you need. You don't even have to add the extra 1440 I showed in my example. Those numbers that divide evenly into 1440 are, 1,2,3,4,5,6,8,10,12,15,18,20,24,30,32,45,60,... and others.
If you need to use numbers like 13 that do not divide evenly into 1440, then the system will have to do an extra bit of calculation as the clock rolls back at midnight. It is a simple operation to adjust the phase with respect to clock time. Otherwise you would have a glitch at midnight and a motor would run too short or to long. Let me know if you need help with code to do that.
The advantage of this approach is that you can use a single RTC, and you let it run, without the subsecond error of resetting it. Tracy Allen www.emesystems.com | | Back to Top | | |
    |  DylanB Registered Member
        Date Joined Feb 2006 Total Posts : 24 | Posted 2/27/2006 6:45 PM (GMT -8) |   | Chris,
I imagine that this device will only operate in increments of minutes-- i.e. we need second-leve precision, but only minute-level time step intervals.
thanks,
Dylan | | Back to Top | | |
 | 46 posts in this thread. Viewing Page : 1 2 | | Forum Information | Currently it is Friday, November 20, 2009 5:57 PM (GMT -8) There are a total of 393,696 posts in 55,520 threads. In the last 3 days there were 88 new threads and 709 reply posts. View Active Threads
| | Who's Online | This forum has 17684 registered members. Please welcome our newest member, Dogg. 64 Guest(s), 12 Registered Member(s) are currently online. Details boeboy, Peter Jakacki, Phil Pilgrim (PhiPi), jazzed, Michael O'Brien, Cluso99, localroger, adranus, Todd Chapman, potatohead, Sal Ammoniac, pharseid |
Forum powered by dotNetBB v2.42EC SP2.02 dotNetBB © 2000-2009 |
|
|