nerve center.cpp
1:/*
2: * Nerve Center statistics and stepper control
3: * for the arduino environment and atmega168
4: *
5: * Cooper Baker 2007 . www.cooperbaker.com
6: *
7: * [tab] = 4
8: *
9: */
10:
11:// [1;1H9-1-1 CALLS ANSWERED THIS SHIFT [K [2;1H1024 [K
12:
13:#include <WProgram.h> // needed by arduino environment
14:
15:#define BAUD 9600 // baud rate
16:#define AVG 120 // number of shifts for averaging
17:#define STEPS 349 // number of steps per revolution - 1
18:#define STEP_COEFF 0.000462963 // step coefficient ( 1 / 2160 ) for demo
19:#define STEP_DLY 25 // milliseconds per half-step (20 hz steps)
20:#define DEMO_CALL_DLY 10000 // milliseconds between demo 'calls'
21:
22://- prototypes -----------------------------------------------------------------
23:void setup( void ); // sets up the chip
24:void loop( void ); // the driver loop
25:void strip_number( char *words ); // makes an integer from the number in the ascii string
26:void stats( void ); // records # calls and does some math
27:void demo_stats( void ); // makes coeff go from 0 - 1 over 6 hours
28:void output( void ); // moves the steppers and txs debug info
29:float scale( float value, float min, float max, float out_min, float out_max );
30:void rx_string( void ); // gets the buffered string
31:void cls( void ); // clears the lcd screen
32:void splash( void ); // fancy splash screen
33:void reset( void ); // reset the data and steppers
34:
35://- variables ------------------------------------------------------------------
36:int maximum[ AVG ]; // averaging AVG maximums
37:char string[ 128 ] = ""; // contains the string
38:int report = 0; // number of report
39:int place = 0; // magnitude of the ascii number
40:int letter = 0; // position within the string
41:int num[ 10 ]; // for ascii to int conversion
42:int n = 0; // numeral counter
43:int i = 0; // for loop counter
44:int calls = 0; // number of 911 calls
45:int prev_calls = 0; // previous calls to detect new shift
46:float average = 0; // average number of calls
47:float coeff = 0; // current call coefficient
48:int full = 0; // full data set flag
49:int demo = LOW; // demo mode flag
50:int update = 1; // update flag
51:int S1 = 0; // stepper 1 step
52:int S2 = 0; // stepper 2 step
53:int S3 = 0; // stepper 3 step
54:int S4 = 0; // stepper 4 step
55:int S5 = 0; // stepper 5 step
56:int S1_prev = 0; // stepper 1 previous step
57:int S2_prev = 0; // stepper 2 previous step
58:int S3_prev = 0; // stepper 3 previous step
59:int S4_prev = 0; // stepper 4 previous step
60:int S5_prev = 0; // stepper 5 previous step
61:
62://- pin setup ------------------------------------------------------------------
63:byte demo_sw = 2; // demo mode pin
64:byte rx_ready = 3; // ready to receive pin
65:byte stepper_1 = 4; // stepper step pins
66:byte stepper_2 = 7; // . . .
67:byte stepper_3 = 8; //
68:byte stepper_4 = 10; //
69:byte stepper_5 = 12; //
70:
71://- setup ----------------------------------------------------------------------
72:void setup( void )
73:{
74: pinMode( demo_sw, INPUT ); // set up demo mode pin
75: pinMode( rx_ready, OUTPUT ); // set up rx_ready pin
76: pinMode( stepper_1, OUTPUT ); // set up stepper pins
77: pinMode( stepper_2, OUTPUT ); // . . .
78: pinMode( stepper_3, OUTPUT ); //
79: pinMode( stepper_4, OUTPUT ); //
80: pinMode( stepper_5, OUTPUT ); //
81:
82: Serial.begin( 9600 ); // connect to serial port
83: cls(); // clear screen
84: splash(); // splash screen
85: cls(); // clear screen
86: digitalWrite( rx_ready, HIGH ); // ready for rx
87:// demo = HIGH;
88:}
89:
90://- loop -----------------------------------------------------------------------
91:void loop( void )
92:{
93: demo = digitalRead( demo_sw );
94: if( demo == HIGH )
95: {
96: demo_stats(); // min to max over 6 hours
97: update = 1; // make sure we output
98: cls(); // clear lcd
99: output(); // pulse the steppers
100: delay( DEMO_CALL_DLY ); // delay between 'calls'
101: }
102: else
103: {
104: rx_string(); // read rx buffer
105: delay( 1000 );
106: strip_number( &string[ 0 ] ); // get the current number of calls
107: stats(); // analyze the data set
108: cls();
109: output(); // pulse the steppers
110: }
111:}
112:
113://- stats ----------------------------------------------------------------------
114:void stats( void )
115:{
116: average = 0; // init average;
117:
118: // this switch ensures that the stats are accurate if we don't have a full data set
119: // i.e. after boot-up or reset, before enough data has been collected to fill the set
120: switch( full ) // full data set?
121: {
122: case 0: for( i = 0 ; i < report ; i++ ) // index increment loop
123:/* not full */ average += maximum[ i ]; // accumulate a sum
124:
125: if( report > 0 ) // if enough values exist to calculate average
126: average = average / report; // calculate average
127: else // otherwise
128: average = calls; // average is current calls
129:
130: break;
131:
132: case 1: for( i = 0 ; i < AVG ; i++ ) // index increment loop
133:/* full */ average += maximum[ i ]; // accumulate a sum
134:
135: average = average / AVG; // calculate average
136: break;
137: }
138:
139: coeff = calls / average; // calculate current coefficient
140: if( coeff > 1 ) // if it is larger than 1
141: coeff = 1; // set it to 1
142:
143: // the next block of if()s calculates the individual steppers' positions
144: // and provides 20% overlap between stepper values
145: if( ( coeff >= 0 ) && ( coeff < 0.25 ) ) // if coeff is in stepper 1 range
146: {
147: if( S1_prev > S1 ) // if new shift
148: S1_prev = 0; // clear previous step value
149: else // else
150: S1_prev = S1; // remember previous step value
151:
152: S1 = scale( coeff, 0.0, 0.25, 0, STEPS ); // calc stepper 1 position
153: }
154:
155: if( ( coeff > 0.20 ) && ( coeff < 0.45 ) ) // etc...
156: {
157: S1 = STEPS;
158:
159: if( S2_prev > S2 )
160: S2_prev = 0;
161: else
162: S2_prev = S2;
163:
164: S2 = scale( coeff, 0.20, 0.45, 0, STEPS );
165: }
166:
167: if( ( coeff > 0.40 ) && ( coeff < 0.65 ) )
168: {
169: S1 = STEPS;
170: S2 = STEPS;
171:
172: if( S3_prev > S3 )
173: S3_prev = 0;
174: else
175: S3_prev = S3;
176:
177: S3 = scale( coeff, 0.40, 0.65, 0, STEPS );
178: }
179: if( ( coeff > 0.60 ) && ( coeff < 0.85 ) )
180: {
181: S1 = STEPS;
182: S2 = STEPS;
183: S3 = STEPS;
184:
185: if( S4_prev > S4 )
186: S4_prev = 0;
187: else
188: S4_prev = S4;
189:
190: S4 = scale( coeff, 0.60, 0.85, 0, STEPS );
191: }
192: if( ( coeff > 0.80 ) && ( coeff < 1 ) )
193: {
194: S1 = STEPS;
195: S2 = STEPS;
196: S3 = STEPS;
197: S4 = STEPS;
198:
199: if( S5_prev > S5 )
200: S5_prev = 0;
201: else
202: S5_prev = S5;
203:
204: S5 = scale( coeff, 0.80, 1.0, 0, STEPS );
205: }
206: if( coeff == 1 )
207: {
208: S1 = STEPS;
209: S2 = STEPS;
210: S3 = STEPS;
211: S4 = STEPS;
212: S5 = STEPS;
213: }
214:}
215:
216://- demo -----------------------------------------------------------------------
217:void demo_stats( void )
218:{
219: coeff = coeff + STEP_COEFF; // increment coefficient
220: if( coeff > 1 ) // if coeff > 1
221: {
222: coeff = 0; // set coeff to 0
223: reset(); // reset steppers and data
224: }
225:
226: // the next block of if()s calculates the individual steppers' positions
227: // and provides 20% overlap between stepper values
228: if( ( coeff >= 0 ) && ( coeff < 0.25 ) ) // if coeff is in stepper 1 range
229: {
230: if( S1_prev > S1 ) // if new shift
231: S1_prev = 0; // clear previous step value
232: else // else
233: S1_prev = S1; // remember previous step value
234:
235: S1 = scale( coeff, 0.0, 0.25, 0, STEPS ); // calc stepper 1 position
236: }
237: if( ( coeff > 0.20 ) && ( coeff < 0.45 ) ) // etc...
238: {
239: S1 = STEPS;
240:
241: if( S2_prev > S2 )
242: S2_prev = 0;
243: else
244: S2_prev = S2;
245:
246: S2 = scale( coeff, 0.20, 0.45, 0, STEPS );
247: }
248: if( ( coeff > 0.40 ) && ( coeff < 0.65 ) )
249: {
250: S1 = STEPS;
251: S2 = STEPS;
252:
253: if( S3_prev > S3 )
254: S3_prev = 0;
255: else
256: S3_prev = S3;
257:
258: S3 = scale( coeff, 0.40, 0.65, 0, STEPS );
259: }
260: if( ( coeff > 0.60 ) && ( coeff < 0.85 ) )
261: {
262: S1 = STEPS;
263: S2 = STEPS;
264: S3 = STEPS;
265:
266: if( S4_prev > S4 )
267: S4_prev = 0;
268: else
269: S4_prev = S4;
270:
271: S4 = scale( coeff, 0.60, 0.85, 0, STEPS );
272: }
273: if( ( coeff > 0.80 ) && ( coeff < 1 ) )
274: {
275: S1 = STEPS;
276: S2 = STEPS;
277: S3 = STEPS;
278: S4 = STEPS;
279:
280: if( S5_prev > S5 )
281: S5_prev = 0;
282: else
283: S5_prev = S5;
284:
285: S5 = scale( coeff, 0.80, 1.0, 0, STEPS );
286: }
287: if( coeff == 1 )
288: {
289: S1 = STEPS;
290: S2 = STEPS;
291: S3 = STEPS;
292: S4 = STEPS;
293: S5 = STEPS;
294: }
295:}
296:
297://- strip_number ---------------------------------------------------------------
298:void strip_number( char *words ) // need to handle serial bug...?
299:{
300: letter = 0;
301: prev_calls = calls;
302: calls = 0;
303: place = 1;
304: n = 0;
305:
306: // the followig for loop reads the first number of calls encountered
307: // in the string, then exits
308: for( i = 0 ; i < 127 ; i++ ) // read the string
309: {
310: if( ( (string[i]=='2') && (string[i+1]==';') ) )
311: { // looking for '2;'
312: letter = i + 4; // index of start of number
313: while( (string[ letter ] > 47) && (string[ letter ] < 58) )
314: { // while letter is ascii numeral
315: num[n] = (int)string[ letter ] - 48; // convert to int and save
316: letter++; // increment letter
317: n++; // increment num index
318: }
319: goto math; // do as i say, not as i do
320: }
321: }
322:
323: // this chunk calculates the value of the ascii numerals
324: math : // how did i get here?
325: while( n-- ) // 'read' the number backwards
326: {
327: calls += num[ n ] * place; // calculate # of calls
328: place *= 10; // increment magnitude
329: }
330:
331: // this if-else determines whether the update flag should be set
332: if( calls == prev_calls ) // need to update output?
333: update = 0; // no update if no data change
334: else
335: update = 1; // update if data change
336:
337: // this handles the Serial.read() bug
338: if( (calls < prev_calls) && (calls > 10) ) // if number is weird
339: {
340: update = 0; // no need to update
341: calls = prev_calls; // set calls to previous calls
342: }
343:
344: // this handles no call data
345: if( calls == 0 ) // if no calls
346: {
347: update = 0; // no need to update
348: calls = prev_calls; // set calls to previous calls
349: }
350:
351: // the next bit of code runs when a new shift occurs and records the previous maximum calls
352: if( calls < prev_calls ) // if the shift is new
353: {
354: maximum[ report ] = prev_calls; // save last shift maximum
355: report++; // increment maximum index
356: if( full == 0 ) // if data set not full
357: {
358: if( report >= AVG ) // if report memory has been filled
359: full = 1; // set full flag
360: }
361: if( report >= AVG ) // if max index needs to be wrapped
362: report = 0; // wrap the maximum index
363: reset(); // reset stepper data/positions
364: }
365:}
366:
367://- reset ----------------------------------------------------------------------
368:void reset( void )
369:{
370: // this while/if combo moves the steppers to maximum position
371: while( ( (S1<STEPS)||(S2<STEPS)||(S3<STEPS)||(S4<STEPS)||(S5<STEPS) ) )
372: { // while not all are max
373: if( S1 < STEPS ) // if S1 is not max
374: {
375: digitalWrite( stepper_1, HIGH ); // pulse the S1 pin
376: S1++; // increment S1
377: }
378: if( S2 < STEPS ) // etc
379: { // . . .
380: digitalWrite( stepper_2, HIGH ); //
381: S2++;
382: }
383: if( S3 < STEPS )
384: {
385: digitalWrite( stepper_3, HIGH );
386: S3++;
387: }
388: if( S4 < STEPS )
389: {
390: digitalWrite( stepper_4, HIGH );
391: S4++;
392: }
393: if( S5 < STEPS )
394: {
395: digitalWrite( stepper_5, HIGH );
396: S5++;
397: }
398: delay( STEP_DLY ); // wait 1/2 step
399: digitalWrite( stepper_1, LOW ); // set stepper pins low
400: digitalWrite( stepper_2, LOW ); // . . .
401: digitalWrite( stepper_3, LOW ); //
402: digitalWrite( stepper_4, LOW );
403: digitalWrite( stepper_5, LOW );
404: delay( STEP_DLY );
405: }
406: for( i = 0 ; i < 50 ; i++ ) // move across the 50 step
407: { // dead zone
408: digitalWrite( stepper_1, HIGH ); // . . .
409: digitalWrite( stepper_2, HIGH ); //
410: digitalWrite( stepper_3, HIGH );
411: digitalWrite( stepper_4, HIGH );
412: digitalWrite( stepper_5, HIGH );
413: delay( STEP_DLY );
414: digitalWrite( stepper_1, LOW );
415: digitalWrite( stepper_2, LOW );
416: digitalWrite( stepper_3, LOW );
417: digitalWrite( stepper_4, LOW );
418: digitalWrite( stepper_5, LOW );
419: delay( STEP_DLY );
420: }
421:
422: S1 = 0; // reset step counts
423: S2 = 0; // . . .
424: S3 = 0; //
425: S4 = 0;
426: S5 = 0;
427: S1_prev = 0;
428: S2_prev = 0;
429: S3_prev = 0;
430: S4_prev = 0;
431: S5_prev = 0;
432:}
433:
434:
435://- output ---------------------------------------------------------------------
436:void output( void )
437:{
438: // print out some formatted debugging data to the tx pin
439: // Calls AvgMax Pct
440: // 12345 12345 100
441: if( demo == HIGH )
442: {
443: Serial.print( "calls avgmax pct" ); // lower case labels
444: Serial.print( (char)254 ); // control mode character
445: Serial.print( (char)192 ); // move to 2,0
446: Serial.print( (int)(coeff * 2160) ); // calls this shift
447: Serial.print( (char)254 ); // control mode character
448: Serial.print( (char)198 ); // move to 2,6
449: Serial.print( 2160 ); // demo avgmax = 2160
450: Serial.print( (char)254 ); // control mode character
451: Serial.print( (char)205 ); // move to 2,13
452: Serial.print( (int)(coeff * 100 ) ); // percent of max
453: }
454: else
455: {
456: Serial.print( "Calls AvgMax Pct" ); // capitalized labels
457: Serial.print( (char)254 ); // control mode character
458: Serial.print( (char)192 ); // move to 2,0
459: Serial.print( calls ); // calls this shift
460: Serial.print( (char)254 ); // control mode character
461: Serial.print( (char)198 ); // move to 2,6
462: Serial.print( (int)average ); // averaged maximum
463: Serial.print( (char)254 ); // control mode character
464: Serial.print( (char)205 ); // move to 2,13
465: Serial.print( (int)(coeff * 100 ) ); // percent of max
466: }
467:
468: // the following while loops change stepper location
469: // by pulsing discrete pins with single-step resolution
470: if( update == 1 )
471: {
472: while( ( (S1_prev<S1)||(S2_prev<S2)||(S3_prev<S3)||(S4_prev<S4)||(S5_prev<S5) ) )
473: { // while steps remain
474: if( S1_prev < S1 ) // if stepper 1 has steps
475: { //
476: digitalWrite( stepper_1, HIGH ); // pulse stepper 1 pin
477: S1_prev++; // increment S1 steps
478: } //
479: if( S2_prev < S2 ) // . . .
480: { //
481: digitalWrite( stepper_2, HIGH );
482: S2_prev++;
483: }
484: if( S3_prev < S3 )
485: {
486: digitalWrite( stepper_3, HIGH );
487: S3_prev++;
488: }
489: if( S4_prev < S4 )
490: {
491: digitalWrite( stepper_4, HIGH );
492: S4_prev++;
493: }
494: if( S5_prev < S5 )
495: {
496: digitalWrite( stepper_5, HIGH );
497: S5_prev++;
498: }
499: delay( STEP_DLY ); // delay 1/2 pulse
500: digitalWrite( stepper_1, LOW ); // set stepper pins low
501: digitalWrite( stepper_2, LOW ); // . . .
502: digitalWrite( stepper_3, LOW ); //
503: digitalWrite( stepper_4, LOW );
504: digitalWrite( stepper_5, LOW );
505: delay( STEP_DLY ); // delay 1/2 pulse
506: }
507: }
508:}
509:
510://- scale ----------------------------------------------------------------------
511:float scale( float value, float min, float max, float out_min, float out_max )
512:{
513: float scaled = ( ( ( value - min ) / ( max - min ) ) * ( out_max - out_min ) ) + out_min;
514: return scaled; // fish have scales too
515:}
516:
517://- read_string ----------------------------------------------------------------
518:void rx_string()
519:{
520: i = 0;
521: if( Serial.available() ) // if a string is buffered
522: {
523: while( serialAvailable() ) // do while data exists
524: {
525: string[ i ] = Serial.read(); // store a character
526: Serial.print( string[ i ] ); // print the character
527: i++; // increment string index
528: }
529: Serial.flush(); // flush serial buffer
530: }
531:}
532:
533://- cls ------------------------------------------------------------------------
534:void cls( void )
535:{
536: Serial.print( (char)254 ); // control character
537: Serial.print( (char)1 ); // clear the display
538:}
539:
540://- splash ---------------------------------------------------------------------
541:void splash( void )
542:{
543: for( i = 0 ; i < 11 ; i++ ) // scroll loop
544: {
545: cls(); // clear the screen
546: Serial.print( (char)254 ); // control character
547: Serial.print( (char)( 128 + ( 10 - i ) ) ); // move cursor
548: Serial.print( "Nerve" ); // print 'Nerve'
549: Serial.print( (char)254 ); // control character
550: Serial.print( (char)( 192 + ( 10 - i ) ) ); // move cursor
551: Serial.print( "Logic" ); // print 'Logic'
552: delay( 150 ); // 1 'frame' = 150 msec
553: }
554: Serial.print( (char)254 ); // control character
555: Serial.print( (char)204 ); // move cursor
556: Serial.print( "2007" ); // print '2007'
557: delay( 2000 ); // pause 2 seconds
558: Serial.flush();
559:}
560:
[